* [PATCH v2] RISC-V: Implement target attribute
@ 2023-11-14 14:15 Kito Cheng
2023-11-14 14:17 ` Kito Cheng
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Kito Cheng @ 2023-11-14 14:15 UTC (permalink / raw)
To: gcc-patches, kito.cheng, palmer, jeffreyalaw; +Cc: Kito Cheng
The target attribute which proposed in [1], target attribute allow user
to specify a local setting per-function basis.
The syntax of target attribute is `__attribute__((target("<ATTR-STRING>")))`.
and the syntax of `<ATTR-STRING>` describes below:
```
ATTR-STRING := ATTR-STRING ';' ATTR
| ATTR
ATTR := ARCH-ATTR
| CPU-ATTR
| TUNE-ATTR
ARCH-ATTR := 'arch=' EXTENSIONS-OR-FULLARCH
EXTENSIONS-OR-FULLARCH := <EXTENSIONS>
| <FULLARCHSTR>
EXTENSIONS := <EXTENSION> ',' <EXTENSIONS>
| <EXTENSION>
FULLARCHSTR := <full-arch-string>
EXTENSION := <OP> <EXTENSION-NAME> <VERSION>
OP := '+'
VERSION := [0-9]+ 'p' [0-9]+
| [1-9][0-9]*
|
EXTENSION-NAME := Naming rule is defined in RISC-V ISA manual
CPU-ATTR := 'cpu=' <valid-cpu-name>
TUNE-ATTR := 'tune=' <valid-tune-name>
```
Changes since v1:
- Use std::unique_ptr rather than alloca to prevent memory issue.
- Error rather than warning when attribute duplicated.
[1] https://github.com/riscv-non-isa/riscv-c-api-doc/pull/35
gcc/ChangeLog:
* config.gcc (riscv): Add riscv-target-attr.o.
* config/riscv/riscv-protos.h (riscv_declare_function_size) New.
(riscv_option_valid_attribute_p): New.
(riscv_override_options_internal): New.
(struct riscv_tune_info): New.
(riscv_parse_tune): New.
* config/riscv/riscv-target-attr.cc
(class riscv_target_attr_parser): New.
(struct riscv_attribute_info): New.
(riscv_attributes): New.
(riscv_target_attr_parser::parse_arch):
(riscv_target_attr_parser::handle_arch):
(riscv_target_attr_parser::handle_cpu):
(riscv_target_attr_parser::handle_tune):
(riscv_target_attr_parser::update_settings):
(riscv_process_one_target_attr):
(num_occurences_in_str):
(riscv_process_target_attr):
(riscv_option_valid_attribute_p):
* config/riscv/riscv.cc: Include target-globals.h and
riscv-subset.h.
(struct riscv_tune_info): Move to riscv-protos.h.
(get_tune_str):
(riscv_parse_tune):
(riscv_declare_function_size):
(riscv_option_override): Build target_option_default_node and
target_option_current_node.
(riscv_save_restore_target_globals):
(riscv_option_restore):
(riscv_previous_fndecl):
(riscv_set_current_function): Apply the target attribute.
(TARGET_OPTION_RESTORE): Define.
(TARGET_OPTION_VALID_ATTRIBUTE_P): Ditto.
* config/riscv/riscv.h (SWITCHABLE_TARGET): Define to 1.
(ASM_DECLARE_FUNCTION_SIZE) Define.
* config/riscv/riscv.opt (mtune=): Add Save attribute.
(mcpu=): Ditto.
(mcmodel=): Ditto.
* config/riscv/t-riscv: Add build rule for riscv-target-attr.o
* doc/extend.texi: Add doc for target attribute.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/target-attr-01.c: New.
* gcc.target/riscv/target-attr-02.c: Ditto.
* gcc.target/riscv/target-attr-03.c: Ditto.
* gcc.target/riscv/target-attr-04.c: Ditto.
* gcc.target/riscv/target-attr-05.c: Ditto.
* gcc.target/riscv/target-attr-06.c: Ditto.
* gcc.target/riscv/target-attr-07.c: Ditto.
* gcc.target/riscv/target-attr-bad-01.c: Ditto.
* gcc.target/riscv/target-attr-bad-02.c: Ditto.
* gcc.target/riscv/target-attr-bad-03.c: Ditto.
* gcc.target/riscv/target-attr-bad-04.c: Ditto.
* gcc.target/riscv/target-attr-bad-05.c: Ditto.
* gcc.target/riscv/target-attr-bad-06.c: Ditto.
* gcc.target/riscv/target-attr-bad-07.c: Ditto.
* gcc.target/riscv/target-attr-bad-08.c: Ditto.
* gcc.target/riscv/target-attr-bad-09.c: Ditto.
* gcc.target/riscv/target-attr-bad-10.c: Ditto.
---
gcc/config.gcc | 2 +-
gcc/config/riscv/riscv-protos.h | 21 +
gcc/config/riscv/riscv-target-attr.cc | 395 ++++++++++++++++++
gcc/config/riscv/riscv.cc | 192 +++++++--
gcc/config/riscv/riscv.h | 6 +
gcc/config/riscv/riscv.opt | 6 +-
gcc/config/riscv/t-riscv | 5 +
gcc/doc/extend.texi | 58 +++
.../gcc.target/riscv/target-attr-01.c | 31 ++
.../gcc.target/riscv/target-attr-02.c | 31 ++
.../gcc.target/riscv/target-attr-03.c | 26 ++
.../gcc.target/riscv/target-attr-04.c | 28 ++
.../gcc.target/riscv/target-attr-05.c | 27 ++
.../gcc.target/riscv/target-attr-06.c | 27 ++
.../gcc.target/riscv/target-attr-07.c | 25 ++
.../gcc.target/riscv/target-attr-bad-01.c | 13 +
.../gcc.target/riscv/target-attr-bad-02.c | 13 +
.../gcc.target/riscv/target-attr-bad-03.c | 13 +
.../gcc.target/riscv/target-attr-bad-04.c | 13 +
.../gcc.target/riscv/target-attr-bad-05.c | 13 +
.../gcc.target/riscv/target-attr-bad-06.c | 13 +
.../gcc.target/riscv/target-attr-bad-07.c | 13 +
.../gcc.target/riscv/target-attr-bad-08.c | 8 +
.../gcc.target/riscv/target-attr-bad-09.c | 8 +
.../gcc.target/riscv/target-attr-bad-10.c | 8 +
25 files changed, 950 insertions(+), 45 deletions(-)
create mode 100644 gcc/config/riscv/riscv-target-attr.cc
create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-01.c
create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-02.c
create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-03.c
create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-04.c
create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-05.c
create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-06.c
create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-07.c
create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-01.c
create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-02.c
create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-03.c
create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-04.c
create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-05.c
create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-06.c
create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-07.c
create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-08.c
create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-09.c
create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-10.c
diff --git a/gcc/config.gcc b/gcc/config.gcc
index ba6d63e33ac..0e86e60629e 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -546,7 +546,7 @@ riscv*)
extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o riscv-selftests.o riscv-string.o"
extra_objs="${extra_objs} riscv-v.o riscv-vsetvl.o riscv-vector-costs.o riscv-avlprop.o"
extra_objs="${extra_objs} riscv-vector-builtins.o riscv-vector-builtins-shapes.o riscv-vector-builtins-bases.o"
- extra_objs="${extra_objs} thead.o"
+ extra_objs="${extra_objs} thead.o riscv-target-attr.o"
d_target_objs="riscv-d.o"
extra_headers="riscv_vector.h"
target_gtfiles="$target_gtfiles \$(srcdir)/config/riscv/riscv-vector-builtins.cc"
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 8cdfadbcf10..196b53f10f3 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -124,6 +124,7 @@ extern void riscv_split_doubleword_move (rtx, rtx);
extern const char *riscv_output_move (rtx, rtx);
extern const char *riscv_output_return ();
extern void riscv_declare_function_name (FILE *, const char *, tree);
+extern void riscv_declare_function_size (FILE *, const char *, tree);
extern void riscv_asm_output_alias (FILE *, const tree, const tree);
extern void riscv_asm_output_external (FILE *, const tree, const char *);
extern bool
@@ -647,5 +648,25 @@ extern bool th_print_operand_address (FILE *, machine_mode, rtx);
extern bool riscv_use_divmod_expander (void);
void riscv_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int);
+extern bool
+riscv_option_valid_attribute_p (tree, tree, tree, int);
+extern void
+riscv_override_options_internal (struct gcc_options *);
+
+struct riscv_tune_param;
+/* Information about one micro-arch we know about. */
+struct riscv_tune_info {
+ /* This micro-arch canonical name. */
+ const char *name;
+
+ /* Which automaton to use for tuning. */
+ enum riscv_microarchitecture_type microarchitecture;
+
+ /* Tuning parameters for this micro-arch. */
+ const struct riscv_tune_param *tune_param;
+};
+
+const struct riscv_tune_info *
+riscv_parse_tune (const char *, bool);
#endif /* ! GCC_RISCV_PROTOS_H */
diff --git a/gcc/config/riscv/riscv-target-attr.cc b/gcc/config/riscv/riscv-target-attr.cc
new file mode 100644
index 00000000000..78f259d0c96
--- /dev/null
+++ b/gcc/config/riscv/riscv-target-attr.cc
@@ -0,0 +1,395 @@
+/* Subroutines used for parsing target attribute for RISC-V.
+ Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#define IN_TARGET_CODE 1
+
+#define INCLUDE_MEMORY
+#define INCLUDE_STRING
+#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"
+#include "riscv-subset.h"
+
+namespace {
+class riscv_target_attr_parser
+{
+public:
+ riscv_target_attr_parser (location_t loc)
+ : m_found_arch_p (false)
+ , m_found_tune_p (false)
+ , m_found_cpu_p (false)
+ , m_subset_list (nullptr)
+ , m_loc (loc)
+ , m_cpu_info (nullptr)
+ , m_tune (nullptr)
+ {
+ }
+
+ bool handle_arch (const char *);
+ bool handle_cpu (const char *);
+ bool handle_tune (const char *);
+
+ void set_loc (location_t loc) {
+ m_loc = loc;
+ }
+
+ void update_settings (struct gcc_options *opts) const;
+private:
+ const char *m_raw_attr_str;
+ bool parse_arch (const char *);
+
+ bool m_found_arch_p;
+ bool m_found_tune_p;
+ bool m_found_cpu_p;
+ riscv_subset_list *m_subset_list;
+ location_t m_loc;
+ const riscv_cpu_info *m_cpu_info;
+ const char *m_tune;
+};
+}
+
+/* All the information needed to handle a target attribute.
+ NAME is the name of the attribute.
+ HANDLER is the function that takes the attribute string as an argument. */
+
+struct riscv_attribute_info
+{
+ const char *name;
+ bool (riscv_target_attr_parser::*handler) (const char *);
+};
+
+/* The target attributes that we support. */
+
+static const struct riscv_attribute_info riscv_attributes[]
+ = {{"arch", &riscv_target_attr_parser::handle_arch},
+ {"cpu", &riscv_target_attr_parser::handle_cpu},
+ {"tune", &riscv_target_attr_parser::handle_tune}};
+
+bool
+riscv_target_attr_parser::parse_arch (const char *str)
+{
+ if (m_subset_list)
+ delete m_subset_list;
+ /* Check if it's setting full arch string. */
+ if (strncmp ("rv", str, strlen ("rv")) == 0)
+ {
+ m_subset_list = riscv_subset_list::parse (str, location_t ());
+
+ if (m_subset_list == nullptr)
+ goto fail;
+
+ return true;
+ }
+ else
+ {
+ /* Parsing the extension list like "+<ext>[,+<ext>]*". */
+ size_t len = strlen (str);
+ std::unique_ptr<char> buf (new char[len]);
+ char *str_to_check = buf.get ();
+ strcpy (str_to_check, str);
+ const char *token = strtok_r (str_to_check, ",", &str_to_check);
+ m_subset_list = riscv_current_subset_list ()->clone ();
+ m_subset_list->set_loc (m_loc);
+ while (token)
+ {
+ if (token[0] != '+')
+ {
+ error_at (
+ m_loc,
+ "unexpected arch for %<target()%> attribute: must start "
+ "with + or rv");
+ goto fail;
+ }
+ else
+ {
+ const char *result = m_subset_list->parse_single_ext (token + 1);
+ /* Check parse_single_ext has consume all string. */
+ if (*result != '\0')
+ {
+ error_at (
+ m_loc,
+ "unexpected arch for %<target()%> attribute: bad "
+ "string found %<%s%>", token);
+ goto fail;
+ }
+ }
+ token = strtok_r (NULL, ",", &str_to_check);
+ }
+ return true;
+ }
+fail:
+ if (m_subset_list != nullptr)
+ {
+ delete m_subset_list;
+ m_subset_list = nullptr;
+ }
+ return false;
+}
+
+/* Handle the ARCH_STR argument to the arch= target attribute. */
+
+bool
+riscv_target_attr_parser::handle_arch (const char *str)
+{
+ if (m_found_arch_p)
+ error_at (m_loc, "%<target()%> attribute: arch appears more than once");
+ m_found_arch_p = true;
+ return parse_arch (str);
+}
+
+/* Handle the CPU_STR argument to the cpu= target attribute. */
+
+bool
+riscv_target_attr_parser::handle_cpu (const char *str)
+{
+ if (m_found_cpu_p)
+ error_at (m_loc, "%<target()%> attribute: cpu appears more than once");
+
+ m_found_cpu_p = true;
+ const riscv_cpu_info *cpu_info = riscv_find_cpu (str);
+
+ if (!cpu_info)
+ {
+ error_at (m_loc, "%<target()%> attribute: unknown CPU %qs", str);
+ return false;
+ }
+
+ if (m_subset_list == nullptr)
+ {
+ const char *arch_str = cpu_info->arch;
+ m_subset_list = riscv_subset_list::parse (arch_str, m_loc);
+ gcc_assert (m_subset_list);
+ }
+
+ m_cpu_info = cpu_info;
+ return true;
+}
+
+/* Handle the TUNE_STR argument to the tune= target attribute. */
+
+bool
+riscv_target_attr_parser::handle_tune (const char *str)
+{
+ if (m_found_tune_p)
+ error_at (m_loc, "%<target()%> attribute: tune appears more than once");
+ m_found_tune_p = true;
+ const struct riscv_tune_info *tune = riscv_parse_tune (str, true);
+
+ if (tune == nullptr)
+ {
+ error_at (m_loc, "%<target()%> attribute: unknown TUNE %qs", str);
+ return false;
+ }
+
+ m_tune = tune->name;
+
+ return true;
+}
+
+void
+riscv_target_attr_parser::update_settings (struct gcc_options *opts) const
+{
+ if (m_subset_list)
+ riscv_set_arch_by_subset_list (m_subset_list, opts);
+
+ if (m_cpu_info)
+ opts->x_riscv_cpu_string = m_cpu_info->name;
+
+ if (m_tune)
+ opts->x_riscv_tune_string = m_tune;
+ else
+ {
+ if (m_cpu_info)
+ opts->x_riscv_tune_string = m_cpu_info->tune;
+ }
+}
+
+/* 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
+riscv_process_one_target_attr (char *arg_str,
+ location_t loc,
+ riscv_target_attr_parser &attr_parser)
+{
+ size_t len = strlen (arg_str);
+
+ if (len == 0)
+ {
+ error_at (loc, "malformed %<target()%> attribute");
+ return false;
+ }
+
+ std::unique_ptr<char> buf (new char[len]);
+ char *str_to_check = buf.get();
+ strcpy (str_to_check, arg_str);
+
+ char *arg = strchr (str_to_check, '=');
+
+ if (!arg)
+ {
+ error_at (
+ loc,
+ "attribute %<target(\"%s\")%> does not accept an argument",
+ str_to_check);
+ return false;
+ }
+
+ arg[0] = '\0';
+ ++arg;
+ for (const auto &attr : riscv_attributes)
+ {
+ /* 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 (strncmp (str_to_check, attr.name, strlen (attr.name)) != 0)
+ continue;
+
+ return (&attr_parser->*attr.handler) (arg);
+ }
+ error_at (loc, "Got unknown attribute %<target(\"%s\")%>", str_to_check);
+
+ return false;
+}
+
+/* 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. */
+
+static bool
+riscv_process_target_attr (tree args, location_t loc, struct gcc_options *opts)
+{
+ if (TREE_CODE (args) == TREE_LIST)
+ {
+ do
+ {
+ tree head = TREE_VALUE (args);
+ if (head)
+ {
+ if (!riscv_process_target_attr (head, loc, opts))
+ 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));
+
+ /* No need to emit warning or error on empty string here, generic code already
+ handle this case. */
+ if (len == 0)
+ {
+ return false;
+ }
+
+ std::unique_ptr<char> buf (new char[len]);
+ char *str_to_check = buf.get ();
+ strcpy (str_to_check, TREE_STRING_POINTER (args));
+
+ /* 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);
+
+ riscv_target_attr_parser attr_parser (loc);
+ unsigned int num_attrs = 0;
+ while (token)
+ {
+ num_attrs++;
+ riscv_process_one_target_attr (token, loc, attr_parser);
+ token = strtok_r (NULL, ";", &str_to_check);
+ }
+
+ if (num_attrs != num_commas + 1)
+ {
+ error_at (loc, "malformed %<target(\"%s\")%> attribute",
+ TREE_STRING_POINTER (args));
+ return false;
+ }
+
+ /* Apply settings from target attribute. */
+ attr_parser.update_settings (opts);
+
+ return true;
+}
+
+/* Implement TARGET_OPTION_VALID_ATTRIBUTE_P. This is used to
+ process attribute ((target ("..."))). */
+
+bool
+riscv_option_valid_attribute_p (tree fndecl, tree, tree args, int)
+{
+ struct cl_target_option cur_target;
+ bool ret;
+ tree new_target;
+ location_t loc = DECL_SOURCE_LOCATION (fndecl);
+
+ /* Save the current target options to restore at the end. */
+ cl_target_option_save (&cur_target, &global_options, &global_options_set);
+
+ ret = riscv_process_target_attr (args, loc, &global_options);
+
+ if (ret)
+ {
+ riscv_override_options_internal (&global_options);
+ new_target
+ = build_target_option_node (&global_options, &global_options_set);
+ }
+ else
+ new_target = NULL;
+
+ if (fndecl && ret)
+ {
+ DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = new_target;
+ }
+
+ cl_target_option_restore (&global_options, &global_options_set, &cur_target);
+ return ret;
+}
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index f09c4066903..cebd2fc0d25 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -73,10 +73,12 @@ along with GCC; see the file COPYING3. If not see
#include "tree-vectorizer.h"
#include "gcse.h"
#include "tree-dfa.h"
+#include "target-globals.h"
/* This file should be included last. */
#include "target-def.h"
#include "riscv-vector-costs.h"
+#include "riscv-subset.h"
/* True if X is an UNSPEC wrapper around a SYMBOL_REF or LABEL_REF. */
#define UNSPEC_ADDRESS_P(X) \
@@ -264,17 +266,6 @@ struct riscv_tune_param
bool use_divmod_expansion;
};
-/* Information about one micro-arch we know about. */
-struct riscv_tune_info {
- /* This micro-arch canonical name. */
- const char *name;
-
- /* Which automaton to use for tuning. */
- enum riscv_microarchitecture_type microarchitecture;
-
- /* Tuning parameters for this micro-arch. */
- const struct riscv_tune_param *tune_param;
-};
/* Global variables for machine-dependent things. */
@@ -501,10 +492,23 @@ riscv_min_arithmetic_precision (void)
return 32;
}
-/* Return the riscv_tune_info entry for the given name string. */
+template <class T>
+static const char *
+get_tune_str (const T *opts)
+{
+ const char *tune_string = RISCV_TUNE_STRING_DEFAULT;
+ if (opts->x_riscv_tune_string)
+ tune_string = opts->x_riscv_tune_string;
+ else if (opts->x_riscv_cpu_string)
+ tune_string = opts->x_riscv_cpu_string;
+ return tune_string;
+}
+
+/* Return the riscv_tune_info entry for the given name string, return nullptr
+ if NULL_P is true, otherwise return an placeholder and report error. */
-static const struct riscv_tune_info *
-riscv_parse_tune (const char *tune_string)
+const struct riscv_tune_info *
+riscv_parse_tune (const char *tune_string, bool null_p)
{
const riscv_cpu_info *cpu = riscv_find_cpu (tune_string);
@@ -515,6 +519,9 @@ riscv_parse_tune (const char *tune_string)
if (strcmp (riscv_tune_info_table[i].name, tune_string) == 0)
return riscv_tune_info_table + i;
+ if (null_p)
+ return nullptr;
+
error ("unknown cpu %qs for %<-mtune%>", tune_string);
return riscv_tune_info_table;
}
@@ -7873,6 +7880,33 @@ riscv_declare_function_name (FILE *stream, const char *name, tree fndecl)
riscv_asm_output_variant_cc (stream, fndecl, name);
ASM_OUTPUT_TYPE_DIRECTIVE (stream, name, "function");
ASM_OUTPUT_LABEL (stream, name);
+ if (DECL_FUNCTION_SPECIFIC_TARGET (fndecl))
+ {
+ fprintf (stream, "\t.option push\n");
+ std::string isa = riscv_current_subset_list ()->to_string (true);
+ fprintf (stream, "\t.option arch, %s\n", isa.c_str ());
+
+ struct cl_target_option *local_cl_target =
+ TREE_TARGET_OPTION (DECL_FUNCTION_SPECIFIC_TARGET (fndecl));
+ struct cl_target_option *global_cl_target =
+ TREE_TARGET_OPTION (target_option_default_node);
+ const char *local_tune_str = get_tune_str (local_cl_target);
+ const char *global_tune_str = get_tune_str (global_cl_target);
+ if (strcmp (local_tune_str, global_tune_str) != 0)
+ fprintf (stream, "\t# tune = %s\n", local_tune_str);
+ }
+}
+
+void
+riscv_declare_function_size (FILE *stream, const char *name, tree fndecl)
+{
+ if (!flag_inhibit_size_directive)
+ ASM_OUTPUT_MEASURED_SIZE (stream, name);
+
+ if (DECL_FUNCTION_SPECIFIC_TARGET (fndecl))
+ {
+ fprintf (stream, "\t.option pop\n");
+ }
}
/* Implement ASM_OUTPUT_DEF_FROM_DECLS. */
@@ -8079,16 +8113,18 @@ riscv_override_options_internal (struct gcc_options *opts)
error ("%<-mdiv%> requires %<-march%> to subsume the %<M%> extension");
/* Likewise floating-point division and square root. */
- if ((TARGET_HARD_FLOAT || TARGET_ZFINX) && (target_flags_explicit & MASK_FDIV) == 0)
+ if ((TARGET_HARD_FLOAT_OPTS_P (opts) || TARGET_ZFINX_OPTS_P (opts))
+ && ((target_flags_explicit & MASK_FDIV) == 0))
opts->x_target_flags |= MASK_FDIV;
/* Handle -mtune, use -mcpu if -mtune is not given, and use default -mtune
if both -mtune and -mcpu are not given. */
- cpu = riscv_parse_tune (opts->x_riscv_tune_string ? opts->x_riscv_tune_string :
- (opts->x_riscv_cpu_string ? opts->x_riscv_cpu_string :
- RISCV_TUNE_STRING_DEFAULT));
+ const char *tune_string = get_tune_str (opts);
+ cpu = riscv_parse_tune (tune_string, false);
riscv_microarchitecture = cpu->microarchitecture;
- tune_param = opts->x_optimize_size ? &optimize_size_tune_info : cpu->tune_param;
+ tune_param = opts->x_optimize_size
+ ? &optimize_size_tune_info
+ : cpu->tune_param;
/* Use -mtune's setting for slow_unaligned_access, even when optimizing
for size. For architectures that trap and emulate unaligned accesses,
@@ -8100,7 +8136,7 @@ riscv_override_options_internal (struct gcc_options *opts)
/* Make a note if user explicity passed -mstrict-align for later
builtin macro generation. Can't use target_flags_explicitly since
it is set even for -mno-strict-align. */
- riscv_user_wants_strict_align = TARGET_STRICT_ALIGN;
+ riscv_user_wants_strict_align = TARGET_STRICT_ALIGN_OPTS_P (opts);
if ((target_flags_explicit & MASK_STRICT_ALIGN) == 0
&& cpu->tune_param->slow_unaligned_access)
@@ -8258,8 +8294,41 @@ riscv_option_override (void)
init_machine_status = &riscv_init_machine_status;
riscv_override_options_internal (&global_options);
+
+ /* Save these options as the default ones in case we push and pop them later
+ while processing functions with potential target attributes. */
+ target_option_default_node = target_option_current_node
+ = build_target_option_node (&global_options, &global_options_set);
+}
+
+/* Restore or save the TREE_TARGET_GLOBALS from or to NEW_TREE.
+ Used by riscv_set_current_function to
+ make sure optab availability predicates are recomputed when necessary. */
+
+void
+riscv_save_restore_target_globals (tree new_tree)
+{
+ if (TREE_TARGET_GLOBALS (new_tree))
+ restore_target_globals (TREE_TARGET_GLOBALS (new_tree));
+ else if (new_tree == target_option_default_node)
+ restore_target_globals (&default_target_globals);
+ else
+ TREE_TARGET_GLOBALS (new_tree) = save_target_globals_default_opts ();
}
+/* Implements TARGET_OPTION_RESTORE. Restore the backend codegen decisions
+ using the information saved in PTR. */
+
+static void
+riscv_option_restore (struct gcc_options *opts,
+ struct gcc_options * /* opts_set */,
+ struct cl_target_option * /* ptr */)
+{
+ riscv_override_options_internal (opts);
+}
+
+static GTY (()) tree riscv_previous_fndecl;
+
/* Implement TARGET_CONDITIONAL_REGISTER_USAGE. */
static void
@@ -8505,7 +8574,12 @@ riscv_get_interrupt_type (tree decl)
return MACHINE_MODE;
}
-/* Implement `TARGET_SET_CURRENT_FUNCTION'. */
+/* Implement `TARGET_SET_CURRENT_FUNCTION'. Unpack the codegen decisions
+ like tuning and ISA features from the DECL_FUNCTION_SPECIFIC_TARGET
+ of the function, if such exists. This function may be called multiple
+ times on a single function so use aarch64_previous_fndecl to avoid
+ setting up identical state. */
+
/* Sanity cheching for above function attributes. */
static void
riscv_set_current_function (tree decl)
@@ -8513,36 +8587,66 @@ riscv_set_current_function (tree decl)
if (decl == NULL_TREE
|| current_function_decl == NULL_TREE
|| current_function_decl == error_mark_node
- || ! cfun->machine
- || cfun->machine->attributes_checked_p)
+ || ! cfun->machine)
return;
- cfun->machine->naked_p = riscv_naked_function_p (decl);
- cfun->machine->interrupt_handler_p
- = riscv_interrupt_type_p (TREE_TYPE (decl));
+ if (!cfun->machine->attributes_checked_p)
+ {
+ cfun->machine->naked_p = riscv_naked_function_p (decl);
+ cfun->machine->interrupt_handler_p
+ = riscv_interrupt_type_p (TREE_TYPE (decl));
- if (cfun->machine->naked_p && cfun->machine->interrupt_handler_p)
- error ("function attributes %qs and %qs are mutually exclusive",
- "interrupt", "naked");
+ if (cfun->machine->naked_p && cfun->machine->interrupt_handler_p)
+ error ("function attributes %qs and %qs are mutually exclusive",
+ "interrupt", "naked");
- if (cfun->machine->interrupt_handler_p)
- {
- tree ret = TREE_TYPE (TREE_TYPE (decl));
- tree args = TYPE_ARG_TYPES (TREE_TYPE (decl));
+ if (cfun->machine->interrupt_handler_p)
+ {
+ tree ret = TREE_TYPE (TREE_TYPE (decl));
+ tree args = TYPE_ARG_TYPES (TREE_TYPE (decl));
+
+ if (TREE_CODE (ret) != VOID_TYPE)
+ error ("%qs function cannot return a value", "interrupt");
- if (TREE_CODE (ret) != VOID_TYPE)
- error ("%qs function cannot return a value", "interrupt");
+ if (args && TREE_CODE (TREE_VALUE (args)) != VOID_TYPE)
+ error ("%qs function cannot have arguments", "interrupt");
- if (args && TREE_CODE (TREE_VALUE (args)) != VOID_TYPE)
- error ("%qs function cannot have arguments", "interrupt");
+ cfun->machine->interrupt_mode = riscv_get_interrupt_type (decl);
- cfun->machine->interrupt_mode = riscv_get_interrupt_type (decl);
+ gcc_assert (cfun->machine->interrupt_mode != UNKNOWN_MODE);
+ }
- gcc_assert (cfun->machine->interrupt_mode != UNKNOWN_MODE);
+ /* Don't print the above diagnostics more than once. */
+ cfun->machine->attributes_checked_p = 1;
}
- /* Don't print the above diagnostics more than once. */
- cfun->machine->attributes_checked_p = 1;
+ if (!decl || decl == riscv_previous_fndecl)
+ return;
+
+ tree old_tree = (riscv_previous_fndecl
+ ? DECL_FUNCTION_SPECIFIC_TARGET (riscv_previous_fndecl)
+ : NULL_TREE);
+
+ tree new_tree = DECL_FUNCTION_SPECIFIC_TARGET (decl);
+
+ /* If current function has no attributes but the previous one did,
+ use the default node. */
+ if (!new_tree && old_tree)
+ new_tree = target_option_default_node;
+
+ /* If nothing to do, return. #pragma GCC reset or #pragma GCC pop to
+ the default have been handled by aarch64_save_restore_target_globals from
+ aarch64_pragma_target_parse. */
+ if (old_tree == new_tree)
+ return;
+
+ riscv_previous_fndecl = decl;
+
+ /* First set the target options. */
+ cl_target_option_restore (&global_options, &global_options_set,
+ TREE_TARGET_OPTION (new_tree));
+
+ riscv_save_restore_target_globals (new_tree);
}
/* Implement TARGET_MERGE_DECL_ATTRIBUTES. */
@@ -9664,6 +9768,12 @@ riscv_preferred_else_value (unsigned ifn, tree vectype, unsigned int nops,
#undef TARGET_OPTION_OVERRIDE
#define TARGET_OPTION_OVERRIDE riscv_option_override
+#undef TARGET_OPTION_RESTORE
+#define TARGET_OPTION_RESTORE riscv_option_restore
+
+#undef TARGET_OPTION_VALID_ATTRIBUTE_P
+#define TARGET_OPTION_VALID_ATTRIBUTE_P riscv_option_valid_attribute_p
+
#undef TARGET_LEGITIMIZE_ADDRESS
#define TARGET_LEGITIMIZE_ADDRESS riscv_legitimize_address
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index 1e9813b4f39..6205d7533f4 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -25,6 +25,8 @@ along with GCC; see the file COPYING3. If not see
#include <stdbool.h>
#include "config/riscv/riscv-opts.h"
+#define SWITCHABLE_TARGET 1
+
/* Target CPU builtins. */
#define TARGET_CPU_CPP_BUILTINS() riscv_cpu_cpp_builtins (pfile)
@@ -1056,6 +1058,10 @@ while (0)
#define ASM_DECLARE_FUNCTION_NAME(STR, NAME, DECL) \
riscv_declare_function_name (STR, NAME, DECL)
+#undef ASM_DECLARE_FUNCTION_SIZE
+#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \
+ riscv_declare_function_size (FILE, FNAME, DECL)
+
/* Add output .variant_cc directive for specific alias definition. */
#undef ASM_OUTPUT_DEF_FROM_DECLS
#define ASM_OUTPUT_DEF_FROM_DECLS(STR, DECL, TARGET) \
diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
index 70d78151cee..1bd661a3fe4 100644
--- a/gcc/config/riscv/riscv.opt
+++ b/gcc/config/riscv/riscv.opt
@@ -84,11 +84,11 @@ Target RejectNegative Joined Negative(march=)
lower-case.
mtune=
-Target RejectNegative Joined Var(riscv_tune_string)
+Target RejectNegative Joined Var(riscv_tune_string) Save
-mtune=PROCESSOR Optimize the output for PROCESSOR.
mcpu=
-Target RejectNegative Joined Var(riscv_cpu_string)
+Target RejectNegative Joined Var(riscv_cpu_string) Save
-mcpu=PROCESSOR Use architecture of and optimize the output for PROCESSOR.
msmall-data-limit=
@@ -106,7 +106,7 @@ memory accesses to be generated as compressed instructions. Currently targets
32-bit integer load/stores.
mcmodel=
-Target RejectNegative Joined Enum(code_model) Var(riscv_cmodel) Init(TARGET_DEFAULT_CMODEL)
+Target RejectNegative Joined Enum(code_model) Var(riscv_cmodel) Init(TARGET_DEFAULT_CMODEL) Save
Specify the code model.
mstrict-align
diff --git a/gcc/config/riscv/t-riscv b/gcc/config/riscv/t-riscv
index 95becfc819b..3b9686daa58 100644
--- a/gcc/config/riscv/t-riscv
+++ b/gcc/config/riscv/t-riscv
@@ -115,6 +115,11 @@ riscv-v.o: $(srcdir)/config/riscv/riscv-v.cc \
$(COMPILE) $<
$(POSTCOMPILE)
+riscv-target-attr.o: $(srcdir)/config/riscv/riscv-target-attr.cc $(CONFIG_H) \
+ $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(DIAGNOSTIC_CORE_H)
+ $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+ $(srcdir)/config/riscv/riscv-target-attr.cc
+
thead.o: $(srcdir)/config/riscv/thead.cc \
$(CONFIG_H) $(SYSTEM_H) coretypes.h $(TARGET_H) backend.h $(RTL_H) \
memmodel.h $(EMIT_RTL_H) poly-int.h output.h
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 7cdfdf8c83b..856dd93d16a 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -6295,8 +6295,66 @@ void f (void) __attribute__ ((interrupt ("user")));
Permissible values for this parameter are @code{user}, @code{supervisor},
and @code{machine}. If there is no parameter, then it defaults to
@code{machine}.
+
+@end table
+
+The following target-specific function attributes are available for the
+RISC-V target. For the most part, these options mirror the behavior of
+similar command-line options (@pxref{RISC-V Options}), but on a
+per-function basis.
+
+@table @code
+@cindex @code{arch=} function attribute, RISC-V
+@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, in addtion, it also support
+extension enablement list, a list of extension name and prefixed with @code{+},
+like @code{arch=+zba} means enable @code{zba} extension.
+Multiple extension can be enabled by separating them with a comma. For example:
+@code{arch=+zba,+zbb}.
+
+@cindex @code{tune=} function attribute, RISC-V
+@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{cpu=} function attribute, RISC-V
+@item cpu=
+Specifies the core for which to tune the performance of this function and also
+whose architectural features to use. The behavior and valid arguments are the
+same as for the @option{-mcpu=} command-line option.
+
@end table
+The above target attributes can be specified as follows:
+
+@smallexample
+__attribute__((target("@var{attr-string}")))
+int
+f (int a)
+@{
+ return a + 5;
+@}
+@end smallexample
+
+where @code{@var{attr-string}} is one of the attribute strings specified above.
+
+Multiple target function attributes can be specified by separating them with
+a semicolon. For example:
+@smallexample
+__attribute__((target("arch=+zba,+zbb;tune=rocket")))
+int
+foo (int a)
+@{
+ return a + 5;
+@}
+@end smallexample
+
+is valid and compiles function @code{foo} with @code{zba}
+and @code{zbb} extensions and tunes it for @code{rocket}.
+
@node RL78 Function Attributes
@subsection RL78 Function Attributes
diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-01.c b/gcc/testsuite/gcc.target/riscv/target-attr-01.c
new file mode 100644
index 00000000000..b3f3d65d543
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/target-attr-01.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
+/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+
+/*
+** foo:
+** ...
+** sh1add\s*a0,a1,a0
+** ...
+*/
+
+
+long foo() __attribute__((target("arch=rv64gc_zba")));
+long foo(long a, long b){
+ return a + (b * 2);
+}
+
+/*
+** bar:
+** ...
+** slli\s*a1,a1,1
+** add\s*a0,a1,a0
+** ...
+*/
+
+
+long bar(long a, long b){
+ return a + (b * 2);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-02.c b/gcc/testsuite/gcc.target/riscv/target-attr-02.c
new file mode 100644
index 00000000000..c010089a823
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/target-attr-02.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
+/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+
+/*
+** foo:
+** ...
+** sh1add\s*a0,a1,a0
+** ...
+*/
+
+
+long foo() __attribute__((target("arch=+zba")));
+long foo(long a, long b){
+ return a + (b * 2);
+}
+
+/*
+** bar:
+** ...
+** slli\s*a1,a1,1
+** add\s*a0,a1,a0
+** ...
+*/
+
+
+long bar(long a, long b){
+ return a + (b * 2);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-03.c b/gcc/testsuite/gcc.target/riscv/target-attr-03.c
new file mode 100644
index 00000000000..b4896cb2e27
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/target-attr-03.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
+/* { dg-options "-march=rv64gc_zba -O2 -mabi=lp64" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+/*
+** foo:
+** ...
+** slli\s*a1,a1,1
+** add\s*a0,a1,a0
+** ...
+*/
+long foo() __attribute__((target("arch=rv64gc")));
+long foo(long a, long b){
+ return a + (b * 2);
+}
+
+/*
+** bar:
+** ...
+** sh1add\s*a0,a1,a0
+** ...
+*/
+long bar(long a, long b){
+ return a + (b * 2);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-04.c b/gcc/testsuite/gcc.target/riscv/target-attr-04.c
new file mode 100644
index 00000000000..369d6514e5a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/target-attr-04.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
+/* { dg-options "-march=rv64gc_zba -O2 -mabi=lp64 -mtune=rocket" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+/*
+** foo:
+** ...
+** # tune = sifive-7-series
+** ...
+** slli\s*a1,a1,1
+** add\s*a0,a1,a0
+** ...
+*/
+long foo() __attribute__((target("cpu=sifive-u74")));
+long foo(long a, long b){
+ return a + (b * 2);
+}
+
+/*
+** bar:
+** ...
+** sh1add\s*a0,a1,a0
+** ...
+*/
+long bar(long a, long b){
+ return a + (b * 2);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-05.c b/gcc/testsuite/gcc.target/riscv/target-attr-05.c
new file mode 100644
index 00000000000..c75368dcebf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/target-attr-05.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
+/* { dg-options "-march=rv64gc_zba -O2 -mabi=lp64 -mtune=rocket" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+/*
+** foo:
+** ...
+** # tune = sifive-7-series
+** ...
+** sh1add\s*a0,a1,a0
+** ...
+*/
+long foo() __attribute__((target("cpu=sifive-u74;arch=rv64gc_zba")));
+long foo(long a, long b){
+ return a + (b * 2);
+}
+
+/*
+** bar:
+** ...
+** sh1add\s*a0,a1,a0
+** ...
+*/
+long bar(long a, long b){
+ return a + (b * 2);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-06.c b/gcc/testsuite/gcc.target/riscv/target-attr-06.c
new file mode 100644
index 00000000000..369c95eeb54
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/target-attr-06.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
+/* { dg-options "-march=rv64gc_zba -O2 -mabi=lp64 -mtune=rocket" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+/*
+** foo:
+** ...
+** # tune = sifive-5-series
+** ...
+** sh1add\s*a0,a1,a0
+** ...
+*/
+long foo() __attribute__((target("cpu=sifive-u74;tune=sifive-5-series;arch=rv64gc_zba")));
+long foo(long a, long b){
+ return a + (b * 2);
+}
+
+/*
+** bar:
+** ...
+** sh1add\s*a0,a1,a0
+** ...
+*/
+long bar(long a, long b){
+ return a + (b * 2);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-07.c b/gcc/testsuite/gcc.target/riscv/target-attr-07.c
new file mode 100644
index 00000000000..4ff81166a62
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/target-attr-07.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
+/* { dg-options "-march=rv64gc_zba -O2 -mabi=lp64 -mtune=rocket" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+/*
+** foo:
+** ...
+** # tune = sifive-5-series
+** ...
+*/
+long foo() __attribute__((target("tune=sifive-5-series")));
+long foo(long a, long b){
+ return a + (b * 2);
+}
+
+/*
+** bar:
+** ...
+** sh1add\s*a0,a1,a0
+** ...
+*/
+long bar(long a, long b){
+ return a + (b * 2);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-01.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-01.c
new file mode 100644
index 00000000000..91cbcaac21d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-01.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
+/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
+
+
+long foo() __attribute__((target("arch=rv64gc_zba;;"))); /* { dg-error "malformed" } */
+long foo(long a, long b){
+ return a + (b * 2);
+}
+
+long bar(long a, long b){
+ return a + (b * 2);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-02.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-02.c
new file mode 100644
index 00000000000..0c838bb3ca7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-02.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
+/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
+
+
+long foo() __attribute__((target("cpu=xyz-cpu"))); /* { dg-error "unknown CPU" } */
+long foo(long a, long b){
+ return a + (b * 2);
+}
+
+long bar(long a, long b){
+ return a + (b * 2);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-03.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-03.c
new file mode 100644
index 00000000000..09702d1690a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-03.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
+/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
+
+
+long foo() __attribute__((target("tune=xyz-cpu"))); /* { dg-error "unknown TUNE" } */
+long foo(long a, long b){
+ return a + (b * 2);
+}
+
+long bar(long a, long b){
+ return a + (b * 2);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-04.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-04.c
new file mode 100644
index 00000000000..1d9a0ffdd88
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-04.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
+/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
+
+
+long foo() __attribute__((target(123))); /* { dg-error "argument not a string" } */
+long foo(long a, long b){
+ return a + (b * 2);
+}
+
+long bar(long a, long b){
+ return a + (b * 2);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-05.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-05.c
new file mode 100644
index 00000000000..24a81c5279b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-05.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
+/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
+
+
+long foo() __attribute__((target(""))); /* { dg-warning "empty string in attribute .target." } */
+long foo(long a, long b){
+ return a + (b * 2);
+}
+
+long bar(long a, long b){
+ return a + (b * 2);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-06.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-06.c
new file mode 100644
index 00000000000..a0d65859d40
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-06.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
+/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
+
+
+long foo() __attribute__((target("arch=*x"))); /* { dg-error "must start with \\+ or rv" } */
+long foo(long a, long b){
+ return a + (b * 2);
+}
+
+long bar(long a, long b){
+ return a + (b * 2);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-07.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-07.c
new file mode 100644
index 00000000000..8aa82504dc1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-07.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
+/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
+
+
+long foo() __attribute__((target("arch=+zbb_zba"))); /* { dg-error "extension 'zbb_zba' starts with 'z' but is unsupported standard extension" } */
+long foo(long a, long b){
+ return a + (b * 2);
+}
+
+long bar(long a, long b){
+ return a + (b * 2);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-08.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-08.c
new file mode 100644
index 00000000000..68d211de887
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-08.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
+/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
+
+long foo() __attribute__((target("arch=rv64gc_zba;arch=rv64gc_zba"))); /* { dg-error "arch appears more than once" } */
+long foo(long a, long b){
+ return a + (b * 2);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-09.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-09.c
new file mode 100644
index 00000000000..2b6e4982894
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-09.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
+/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
+
+long foo() __attribute__((target("cpu=sifive-u74;cpu=sifive-u74"))); /* { dg-error "cpu appears more than once" } */
+long foo(long a, long b){
+ return a + (b * 2);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-10.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-10.c
new file mode 100644
index 00000000000..00cefa03e41
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-10.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
+/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
+
+long foo() __attribute__((target("tune=sifive-u74;tune=sifive-u74"))); /* { dg-error "tune appears more than once" } */
+long foo(long a, long b){
+ return a + (b * 2);
+}
--
2.40.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2] RISC-V: Implement target attribute
2023-11-14 14:15 [PATCH v2] RISC-V: Implement target attribute Kito Cheng
@ 2023-11-14 14:17 ` Kito Cheng
2023-11-15 23:58 ` Christoph Müllner
2023-11-17 15:41 ` Andreas Schwab
2 siblings, 0 replies; 6+ messages in thread
From: Kito Cheng @ 2023-11-14 14:17 UTC (permalink / raw)
To: Kito Cheng; +Cc: gcc-patches, palmer, jeffreyalaw
Oh damm, I found it should be v3, but anyway it's the latest version
for the target attribute support...
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2] RISC-V: Implement target attribute
2023-11-14 14:15 [PATCH v2] RISC-V: Implement target attribute Kito Cheng
2023-11-14 14:17 ` Kito Cheng
@ 2023-11-15 23:58 ` Christoph Müllner
2023-11-16 11:40 ` Kito Cheng
2023-11-17 15:41 ` Andreas Schwab
2 siblings, 1 reply; 6+ messages in thread
From: Christoph Müllner @ 2023-11-15 23:58 UTC (permalink / raw)
To: Kito Cheng; +Cc: gcc-patches, kito.cheng, palmer, jeffreyalaw
On Tue, Nov 14, 2023 at 3:15 PM Kito Cheng <kito.cheng@sifive.com> wrote:
>
> The target attribute which proposed in [1], target attribute allow user
> to specify a local setting per-function basis.
>
> The syntax of target attribute is `__attribute__((target("<ATTR-STRING>")))`.
>
> and the syntax of `<ATTR-STRING>` describes below:
> ```
> ATTR-STRING := ATTR-STRING ';' ATTR
> | ATTR
>
> ATTR := ARCH-ATTR
> | CPU-ATTR
> | TUNE-ATTR
>
> ARCH-ATTR := 'arch=' EXTENSIONS-OR-FULLARCH
>
> EXTENSIONS-OR-FULLARCH := <EXTENSIONS>
> | <FULLARCHSTR>
>
> EXTENSIONS := <EXTENSION> ',' <EXTENSIONS>
> | <EXTENSION>
>
> FULLARCHSTR := <full-arch-string>
>
> EXTENSION := <OP> <EXTENSION-NAME> <VERSION>
>
> OP := '+'
>
> VERSION := [0-9]+ 'p' [0-9]+
> | [1-9][0-9]*
> |
>
> EXTENSION-NAME := Naming rule is defined in RISC-V ISA manual
>
> CPU-ATTR := 'cpu=' <valid-cpu-name>
> TUNE-ATTR := 'tune=' <valid-tune-name>
> ```
>
> Changes since v1:
> - Use std::unique_ptr rather than alloca to prevent memory issue.
> - Error rather than warning when attribute duplicated.
>
> [1] https://github.com/riscv-non-isa/riscv-c-api-doc/pull/35
I've reviewed with a focus on the utilized backend hooks and macros.
Reviewed-by: Christoph Müllner <christoph.muellner@vrull.eu>
Note, that in the changelog below there are quite many empty entries.
>
> gcc/ChangeLog:
>
> * config.gcc (riscv): Add riscv-target-attr.o.
> * config/riscv/riscv-protos.h (riscv_declare_function_size) New.
> (riscv_option_valid_attribute_p): New.
> (riscv_override_options_internal): New.
> (struct riscv_tune_info): New.
> (riscv_parse_tune): New.
> * config/riscv/riscv-target-attr.cc
> (class riscv_target_attr_parser): New.
> (struct riscv_attribute_info): New.
> (riscv_attributes): New.
> (riscv_target_attr_parser::parse_arch):
> (riscv_target_attr_parser::handle_arch):
> (riscv_target_attr_parser::handle_cpu):
> (riscv_target_attr_parser::handle_tune):
> (riscv_target_attr_parser::update_settings):
> (riscv_process_one_target_attr):
> (num_occurences_in_str):
> (riscv_process_target_attr):
> (riscv_option_valid_attribute_p):
> * config/riscv/riscv.cc: Include target-globals.h and
> riscv-subset.h.
> (struct riscv_tune_info): Move to riscv-protos.h.
> (get_tune_str):
> (riscv_parse_tune):
> (riscv_declare_function_size):
> (riscv_option_override): Build target_option_default_node and
> target_option_current_node.
> (riscv_save_restore_target_globals):
> (riscv_option_restore):
> (riscv_previous_fndecl):
> (riscv_set_current_function): Apply the target attribute.
> (TARGET_OPTION_RESTORE): Define.
> (TARGET_OPTION_VALID_ATTRIBUTE_P): Ditto.
> * config/riscv/riscv.h (SWITCHABLE_TARGET): Define to 1.
> (ASM_DECLARE_FUNCTION_SIZE) Define.
> * config/riscv/riscv.opt (mtune=): Add Save attribute.
> (mcpu=): Ditto.
> (mcmodel=): Ditto.
> * config/riscv/t-riscv: Add build rule for riscv-target-attr.o
> * doc/extend.texi: Add doc for target attribute.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.target/riscv/target-attr-01.c: New.
> * gcc.target/riscv/target-attr-02.c: Ditto.
> * gcc.target/riscv/target-attr-03.c: Ditto.
> * gcc.target/riscv/target-attr-04.c: Ditto.
> * gcc.target/riscv/target-attr-05.c: Ditto.
> * gcc.target/riscv/target-attr-06.c: Ditto.
> * gcc.target/riscv/target-attr-07.c: Ditto.
> * gcc.target/riscv/target-attr-bad-01.c: Ditto.
> * gcc.target/riscv/target-attr-bad-02.c: Ditto.
> * gcc.target/riscv/target-attr-bad-03.c: Ditto.
> * gcc.target/riscv/target-attr-bad-04.c: Ditto.
> * gcc.target/riscv/target-attr-bad-05.c: Ditto.
> * gcc.target/riscv/target-attr-bad-06.c: Ditto.
> * gcc.target/riscv/target-attr-bad-07.c: Ditto.
> * gcc.target/riscv/target-attr-bad-08.c: Ditto.
> * gcc.target/riscv/target-attr-bad-09.c: Ditto.
> * gcc.target/riscv/target-attr-bad-10.c: Ditto.
> ---
> gcc/config.gcc | 2 +-
> gcc/config/riscv/riscv-protos.h | 21 +
> gcc/config/riscv/riscv-target-attr.cc | 395 ++++++++++++++++++
> gcc/config/riscv/riscv.cc | 192 +++++++--
> gcc/config/riscv/riscv.h | 6 +
> gcc/config/riscv/riscv.opt | 6 +-
> gcc/config/riscv/t-riscv | 5 +
> gcc/doc/extend.texi | 58 +++
> .../gcc.target/riscv/target-attr-01.c | 31 ++
> .../gcc.target/riscv/target-attr-02.c | 31 ++
> .../gcc.target/riscv/target-attr-03.c | 26 ++
> .../gcc.target/riscv/target-attr-04.c | 28 ++
> .../gcc.target/riscv/target-attr-05.c | 27 ++
> .../gcc.target/riscv/target-attr-06.c | 27 ++
> .../gcc.target/riscv/target-attr-07.c | 25 ++
> .../gcc.target/riscv/target-attr-bad-01.c | 13 +
> .../gcc.target/riscv/target-attr-bad-02.c | 13 +
> .../gcc.target/riscv/target-attr-bad-03.c | 13 +
> .../gcc.target/riscv/target-attr-bad-04.c | 13 +
> .../gcc.target/riscv/target-attr-bad-05.c | 13 +
> .../gcc.target/riscv/target-attr-bad-06.c | 13 +
> .../gcc.target/riscv/target-attr-bad-07.c | 13 +
> .../gcc.target/riscv/target-attr-bad-08.c | 8 +
> .../gcc.target/riscv/target-attr-bad-09.c | 8 +
> .../gcc.target/riscv/target-attr-bad-10.c | 8 +
> 25 files changed, 950 insertions(+), 45 deletions(-)
> create mode 100644 gcc/config/riscv/riscv-target-attr.cc
> create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-01.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-02.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-03.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-04.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-05.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-06.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-07.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-01.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-02.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-03.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-04.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-05.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-06.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-07.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-08.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-09.c
> create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-10.c
>
> diff --git a/gcc/config.gcc b/gcc/config.gcc
> index ba6d63e33ac..0e86e60629e 100644
> --- a/gcc/config.gcc
> +++ b/gcc/config.gcc
> @@ -546,7 +546,7 @@ riscv*)
> extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o riscv-selftests.o riscv-string.o"
> extra_objs="${extra_objs} riscv-v.o riscv-vsetvl.o riscv-vector-costs.o riscv-avlprop.o"
> extra_objs="${extra_objs} riscv-vector-builtins.o riscv-vector-builtins-shapes.o riscv-vector-builtins-bases.o"
> - extra_objs="${extra_objs} thead.o"
> + extra_objs="${extra_objs} thead.o riscv-target-attr.o"
> d_target_objs="riscv-d.o"
> extra_headers="riscv_vector.h"
> target_gtfiles="$target_gtfiles \$(srcdir)/config/riscv/riscv-vector-builtins.cc"
> diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
> index 8cdfadbcf10..196b53f10f3 100644
> --- a/gcc/config/riscv/riscv-protos.h
> +++ b/gcc/config/riscv/riscv-protos.h
> @@ -124,6 +124,7 @@ extern void riscv_split_doubleword_move (rtx, rtx);
> extern const char *riscv_output_move (rtx, rtx);
> extern const char *riscv_output_return ();
> extern void riscv_declare_function_name (FILE *, const char *, tree);
> +extern void riscv_declare_function_size (FILE *, const char *, tree);
> extern void riscv_asm_output_alias (FILE *, const tree, const tree);
> extern void riscv_asm_output_external (FILE *, const tree, const char *);
> extern bool
> @@ -647,5 +648,25 @@ extern bool th_print_operand_address (FILE *, machine_mode, rtx);
>
> extern bool riscv_use_divmod_expander (void);
> void riscv_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int);
> +extern bool
> +riscv_option_valid_attribute_p (tree, tree, tree, int);
> +extern void
> +riscv_override_options_internal (struct gcc_options *);
> +
> +struct riscv_tune_param;
> +/* Information about one micro-arch we know about. */
> +struct riscv_tune_info {
> + /* This micro-arch canonical name. */
> + const char *name;
> +
> + /* Which automaton to use for tuning. */
> + enum riscv_microarchitecture_type microarchitecture;
> +
> + /* Tuning parameters for this micro-arch. */
> + const struct riscv_tune_param *tune_param;
> +};
> +
> +const struct riscv_tune_info *
> +riscv_parse_tune (const char *, bool);
>
> #endif /* ! GCC_RISCV_PROTOS_H */
> diff --git a/gcc/config/riscv/riscv-target-attr.cc b/gcc/config/riscv/riscv-target-attr.cc
> new file mode 100644
> index 00000000000..78f259d0c96
> --- /dev/null
> +++ b/gcc/config/riscv/riscv-target-attr.cc
> @@ -0,0 +1,395 @@
> +/* Subroutines used for parsing target attribute for RISC-V.
> + Copyright (C) 2023 Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify
> +it under the terms of the GNU General Public License as published by
> +the Free Software Foundation; either version 3, or (at your option)
> +any later version.
> +
> +GCC is distributed in the hope that it will be useful,
> +but WITHOUT ANY WARRANTY; without even the implied warranty of
> +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +GNU General Public License for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3. If not see
> +<http://www.gnu.org/licenses/>. */
> +
> +#define IN_TARGET_CODE 1
> +
> +#define INCLUDE_MEMORY
> +#define INCLUDE_STRING
> +#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"
> +#include "riscv-subset.h"
> +
> +namespace {
> +class riscv_target_attr_parser
> +{
> +public:
> + riscv_target_attr_parser (location_t loc)
> + : m_found_arch_p (false)
> + , m_found_tune_p (false)
> + , m_found_cpu_p (false)
> + , m_subset_list (nullptr)
> + , m_loc (loc)
> + , m_cpu_info (nullptr)
> + , m_tune (nullptr)
> + {
> + }
> +
> + bool handle_arch (const char *);
> + bool handle_cpu (const char *);
> + bool handle_tune (const char *);
> +
> + void set_loc (location_t loc) {
> + m_loc = loc;
> + }
> +
> + void update_settings (struct gcc_options *opts) const;
> +private:
> + const char *m_raw_attr_str;
> + bool parse_arch (const char *);
> +
> + bool m_found_arch_p;
> + bool m_found_tune_p;
> + bool m_found_cpu_p;
> + riscv_subset_list *m_subset_list;
> + location_t m_loc;
> + const riscv_cpu_info *m_cpu_info;
> + const char *m_tune;
> +};
> +}
> +
> +/* All the information needed to handle a target attribute.
> + NAME is the name of the attribute.
> + HANDLER is the function that takes the attribute string as an argument. */
> +
> +struct riscv_attribute_info
> +{
> + const char *name;
> + bool (riscv_target_attr_parser::*handler) (const char *);
> +};
> +
> +/* The target attributes that we support. */
> +
> +static const struct riscv_attribute_info riscv_attributes[]
> + = {{"arch", &riscv_target_attr_parser::handle_arch},
> + {"cpu", &riscv_target_attr_parser::handle_cpu},
> + {"tune", &riscv_target_attr_parser::handle_tune}};
> +
> +bool
> +riscv_target_attr_parser::parse_arch (const char *str)
> +{
> + if (m_subset_list)
> + delete m_subset_list;
> + /* Check if it's setting full arch string. */
> + if (strncmp ("rv", str, strlen ("rv")) == 0)
> + {
> + m_subset_list = riscv_subset_list::parse (str, location_t ());
> +
> + if (m_subset_list == nullptr)
> + goto fail;
> +
> + return true;
> + }
> + else
> + {
> + /* Parsing the extension list like "+<ext>[,+<ext>]*". */
> + size_t len = strlen (str);
> + std::unique_ptr<char> buf (new char[len]);
> + char *str_to_check = buf.get ();
> + strcpy (str_to_check, str);
> + const char *token = strtok_r (str_to_check, ",", &str_to_check);
> + m_subset_list = riscv_current_subset_list ()->clone ();
> + m_subset_list->set_loc (m_loc);
> + while (token)
> + {
> + if (token[0] != '+')
> + {
> + error_at (
> + m_loc,
> + "unexpected arch for %<target()%> attribute: must start "
> + "with + or rv");
> + goto fail;
> + }
> + else
> + {
> + const char *result = m_subset_list->parse_single_ext (token + 1);
> + /* Check parse_single_ext has consume all string. */
> + if (*result != '\0')
> + {
> + error_at (
> + m_loc,
> + "unexpected arch for %<target()%> attribute: bad "
> + "string found %<%s%>", token);
> + goto fail;
> + }
> + }
> + token = strtok_r (NULL, ",", &str_to_check);
> + }
> + return true;
> + }
> +fail:
> + if (m_subset_list != nullptr)
> + {
> + delete m_subset_list;
> + m_subset_list = nullptr;
> + }
> + return false;
> +}
> +
> +/* Handle the ARCH_STR argument to the arch= target attribute. */
> +
> +bool
> +riscv_target_attr_parser::handle_arch (const char *str)
> +{
> + if (m_found_arch_p)
> + error_at (m_loc, "%<target()%> attribute: arch appears more than once");
> + m_found_arch_p = true;
> + return parse_arch (str);
> +}
> +
> +/* Handle the CPU_STR argument to the cpu= target attribute. */
> +
> +bool
> +riscv_target_attr_parser::handle_cpu (const char *str)
> +{
> + if (m_found_cpu_p)
> + error_at (m_loc, "%<target()%> attribute: cpu appears more than once");
> +
> + m_found_cpu_p = true;
> + const riscv_cpu_info *cpu_info = riscv_find_cpu (str);
> +
> + if (!cpu_info)
> + {
> + error_at (m_loc, "%<target()%> attribute: unknown CPU %qs", str);
> + return false;
> + }
> +
> + if (m_subset_list == nullptr)
> + {
> + const char *arch_str = cpu_info->arch;
> + m_subset_list = riscv_subset_list::parse (arch_str, m_loc);
> + gcc_assert (m_subset_list);
> + }
> +
> + m_cpu_info = cpu_info;
> + return true;
> +}
> +
> +/* Handle the TUNE_STR argument to the tune= target attribute. */
> +
> +bool
> +riscv_target_attr_parser::handle_tune (const char *str)
> +{
> + if (m_found_tune_p)
> + error_at (m_loc, "%<target()%> attribute: tune appears more than once");
> + m_found_tune_p = true;
> + const struct riscv_tune_info *tune = riscv_parse_tune (str, true);
> +
> + if (tune == nullptr)
> + {
> + error_at (m_loc, "%<target()%> attribute: unknown TUNE %qs", str);
> + return false;
> + }
> +
> + m_tune = tune->name;
> +
> + return true;
> +}
> +
> +void
> +riscv_target_attr_parser::update_settings (struct gcc_options *opts) const
> +{
> + if (m_subset_list)
> + riscv_set_arch_by_subset_list (m_subset_list, opts);
> +
> + if (m_cpu_info)
> + opts->x_riscv_cpu_string = m_cpu_info->name;
> +
> + if (m_tune)
> + opts->x_riscv_tune_string = m_tune;
> + else
> + {
> + if (m_cpu_info)
> + opts->x_riscv_tune_string = m_cpu_info->tune;
> + }
> +}
> +
> +/* 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
> +riscv_process_one_target_attr (char *arg_str,
> + location_t loc,
> + riscv_target_attr_parser &attr_parser)
> +{
> + size_t len = strlen (arg_str);
> +
> + if (len == 0)
> + {
> + error_at (loc, "malformed %<target()%> attribute");
> + return false;
> + }
> +
> + std::unique_ptr<char> buf (new char[len]);
> + char *str_to_check = buf.get();
> + strcpy (str_to_check, arg_str);
> +
> + char *arg = strchr (str_to_check, '=');
> +
> + if (!arg)
> + {
> + error_at (
> + loc,
> + "attribute %<target(\"%s\")%> does not accept an argument",
> + str_to_check);
> + return false;
> + }
> +
> + arg[0] = '\0';
> + ++arg;
> + for (const auto &attr : riscv_attributes)
> + {
> + /* 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 (strncmp (str_to_check, attr.name, strlen (attr.name)) != 0)
> + continue;
> +
> + return (&attr_parser->*attr.handler) (arg);
> + }
> + error_at (loc, "Got unknown attribute %<target(\"%s\")%>", str_to_check);
> +
> + return false;
> +}
> +
> +/* 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. */
> +
> +static bool
> +riscv_process_target_attr (tree args, location_t loc, struct gcc_options *opts)
> +{
> + if (TREE_CODE (args) == TREE_LIST)
> + {
> + do
> + {
> + tree head = TREE_VALUE (args);
> + if (head)
> + {
> + if (!riscv_process_target_attr (head, loc, opts))
> + 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));
> +
> + /* No need to emit warning or error on empty string here, generic code already
> + handle this case. */
> + if (len == 0)
> + {
> + return false;
> + }
> +
> + std::unique_ptr<char> buf (new char[len]);
> + char *str_to_check = buf.get ();
> + strcpy (str_to_check, TREE_STRING_POINTER (args));
> +
> + /* 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);
> +
> + riscv_target_attr_parser attr_parser (loc);
> + unsigned int num_attrs = 0;
> + while (token)
> + {
> + num_attrs++;
> + riscv_process_one_target_attr (token, loc, attr_parser);
> + token = strtok_r (NULL, ";", &str_to_check);
> + }
> +
> + if (num_attrs != num_commas + 1)
> + {
> + error_at (loc, "malformed %<target(\"%s\")%> attribute",
> + TREE_STRING_POINTER (args));
> + return false;
> + }
> +
> + /* Apply settings from target attribute. */
> + attr_parser.update_settings (opts);
> +
> + return true;
> +}
> +
> +/* Implement TARGET_OPTION_VALID_ATTRIBUTE_P. This is used to
> + process attribute ((target ("..."))). */
> +
> +bool
> +riscv_option_valid_attribute_p (tree fndecl, tree, tree args, int)
> +{
> + struct cl_target_option cur_target;
> + bool ret;
> + tree new_target;
> + location_t loc = DECL_SOURCE_LOCATION (fndecl);
> +
> + /* Save the current target options to restore at the end. */
> + cl_target_option_save (&cur_target, &global_options, &global_options_set);
> +
> + ret = riscv_process_target_attr (args, loc, &global_options);
> +
> + if (ret)
> + {
> + riscv_override_options_internal (&global_options);
> + new_target
> + = build_target_option_node (&global_options, &global_options_set);
> + }
> + else
> + new_target = NULL;
> +
> + if (fndecl && ret)
> + {
> + DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = new_target;
> + }
> +
> + cl_target_option_restore (&global_options, &global_options_set, &cur_target);
> + return ret;
> +}
> diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
> index f09c4066903..cebd2fc0d25 100644
> --- a/gcc/config/riscv/riscv.cc
> +++ b/gcc/config/riscv/riscv.cc
> @@ -73,10 +73,12 @@ along with GCC; see the file COPYING3. If not see
> #include "tree-vectorizer.h"
> #include "gcse.h"
> #include "tree-dfa.h"
> +#include "target-globals.h"
>
> /* This file should be included last. */
> #include "target-def.h"
> #include "riscv-vector-costs.h"
> +#include "riscv-subset.h"
>
> /* True if X is an UNSPEC wrapper around a SYMBOL_REF or LABEL_REF. */
> #define UNSPEC_ADDRESS_P(X) \
> @@ -264,17 +266,6 @@ struct riscv_tune_param
> bool use_divmod_expansion;
> };
>
> -/* Information about one micro-arch we know about. */
> -struct riscv_tune_info {
> - /* This micro-arch canonical name. */
> - const char *name;
> -
> - /* Which automaton to use for tuning. */
> - enum riscv_microarchitecture_type microarchitecture;
> -
> - /* Tuning parameters for this micro-arch. */
> - const struct riscv_tune_param *tune_param;
> -};
>
> /* Global variables for machine-dependent things. */
>
> @@ -501,10 +492,23 @@ riscv_min_arithmetic_precision (void)
> return 32;
> }
>
> -/* Return the riscv_tune_info entry for the given name string. */
> +template <class T>
> +static const char *
> +get_tune_str (const T *opts)
> +{
> + const char *tune_string = RISCV_TUNE_STRING_DEFAULT;
> + if (opts->x_riscv_tune_string)
> + tune_string = opts->x_riscv_tune_string;
> + else if (opts->x_riscv_cpu_string)
> + tune_string = opts->x_riscv_cpu_string;
> + return tune_string;
> +}
> +
> +/* Return the riscv_tune_info entry for the given name string, return nullptr
> + if NULL_P is true, otherwise return an placeholder and report error. */
>
> -static const struct riscv_tune_info *
> -riscv_parse_tune (const char *tune_string)
> +const struct riscv_tune_info *
> +riscv_parse_tune (const char *tune_string, bool null_p)
> {
> const riscv_cpu_info *cpu = riscv_find_cpu (tune_string);
>
> @@ -515,6 +519,9 @@ riscv_parse_tune (const char *tune_string)
> if (strcmp (riscv_tune_info_table[i].name, tune_string) == 0)
> return riscv_tune_info_table + i;
>
> + if (null_p)
> + return nullptr;
> +
> error ("unknown cpu %qs for %<-mtune%>", tune_string);
> return riscv_tune_info_table;
> }
> @@ -7873,6 +7880,33 @@ riscv_declare_function_name (FILE *stream, const char *name, tree fndecl)
> riscv_asm_output_variant_cc (stream, fndecl, name);
> ASM_OUTPUT_TYPE_DIRECTIVE (stream, name, "function");
> ASM_OUTPUT_LABEL (stream, name);
> + if (DECL_FUNCTION_SPECIFIC_TARGET (fndecl))
> + {
> + fprintf (stream, "\t.option push\n");
> + std::string isa = riscv_current_subset_list ()->to_string (true);
> + fprintf (stream, "\t.option arch, %s\n", isa.c_str ());
> +
> + struct cl_target_option *local_cl_target =
> + TREE_TARGET_OPTION (DECL_FUNCTION_SPECIFIC_TARGET (fndecl));
> + struct cl_target_option *global_cl_target =
> + TREE_TARGET_OPTION (target_option_default_node);
> + const char *local_tune_str = get_tune_str (local_cl_target);
> + const char *global_tune_str = get_tune_str (global_cl_target);
> + if (strcmp (local_tune_str, global_tune_str) != 0)
> + fprintf (stream, "\t# tune = %s\n", local_tune_str);
> + }
> +}
> +
> +void
> +riscv_declare_function_size (FILE *stream, const char *name, tree fndecl)
> +{
> + if (!flag_inhibit_size_directive)
> + ASM_OUTPUT_MEASURED_SIZE (stream, name);
> +
> + if (DECL_FUNCTION_SPECIFIC_TARGET (fndecl))
> + {
> + fprintf (stream, "\t.option pop\n");
> + }
> }
>
> /* Implement ASM_OUTPUT_DEF_FROM_DECLS. */
> @@ -8079,16 +8113,18 @@ riscv_override_options_internal (struct gcc_options *opts)
> error ("%<-mdiv%> requires %<-march%> to subsume the %<M%> extension");
>
> /* Likewise floating-point division and square root. */
> - if ((TARGET_HARD_FLOAT || TARGET_ZFINX) && (target_flags_explicit & MASK_FDIV) == 0)
> + if ((TARGET_HARD_FLOAT_OPTS_P (opts) || TARGET_ZFINX_OPTS_P (opts))
> + && ((target_flags_explicit & MASK_FDIV) == 0))
> opts->x_target_flags |= MASK_FDIV;
>
> /* Handle -mtune, use -mcpu if -mtune is not given, and use default -mtune
> if both -mtune and -mcpu are not given. */
> - cpu = riscv_parse_tune (opts->x_riscv_tune_string ? opts->x_riscv_tune_string :
> - (opts->x_riscv_cpu_string ? opts->x_riscv_cpu_string :
> - RISCV_TUNE_STRING_DEFAULT));
> + const char *tune_string = get_tune_str (opts);
> + cpu = riscv_parse_tune (tune_string, false);
> riscv_microarchitecture = cpu->microarchitecture;
> - tune_param = opts->x_optimize_size ? &optimize_size_tune_info : cpu->tune_param;
> + tune_param = opts->x_optimize_size
> + ? &optimize_size_tune_info
> + : cpu->tune_param;
>
> /* Use -mtune's setting for slow_unaligned_access, even when optimizing
> for size. For architectures that trap and emulate unaligned accesses,
> @@ -8100,7 +8136,7 @@ riscv_override_options_internal (struct gcc_options *opts)
> /* Make a note if user explicity passed -mstrict-align for later
> builtin macro generation. Can't use target_flags_explicitly since
> it is set even for -mno-strict-align. */
> - riscv_user_wants_strict_align = TARGET_STRICT_ALIGN;
> + riscv_user_wants_strict_align = TARGET_STRICT_ALIGN_OPTS_P (opts);
>
> if ((target_flags_explicit & MASK_STRICT_ALIGN) == 0
> && cpu->tune_param->slow_unaligned_access)
> @@ -8258,8 +8294,41 @@ riscv_option_override (void)
> init_machine_status = &riscv_init_machine_status;
>
> riscv_override_options_internal (&global_options);
> +
> + /* Save these options as the default ones in case we push and pop them later
> + while processing functions with potential target attributes. */
> + target_option_default_node = target_option_current_node
> + = build_target_option_node (&global_options, &global_options_set);
> +}
> +
> +/* Restore or save the TREE_TARGET_GLOBALS from or to NEW_TREE.
> + Used by riscv_set_current_function to
> + make sure optab availability predicates are recomputed when necessary. */
> +
> +void
> +riscv_save_restore_target_globals (tree new_tree)
> +{
> + if (TREE_TARGET_GLOBALS (new_tree))
> + restore_target_globals (TREE_TARGET_GLOBALS (new_tree));
> + else if (new_tree == target_option_default_node)
> + restore_target_globals (&default_target_globals);
> + else
> + TREE_TARGET_GLOBALS (new_tree) = save_target_globals_default_opts ();
> }
>
> +/* Implements TARGET_OPTION_RESTORE. Restore the backend codegen decisions
> + using the information saved in PTR. */
> +
> +static void
> +riscv_option_restore (struct gcc_options *opts,
> + struct gcc_options * /* opts_set */,
> + struct cl_target_option * /* ptr */)
> +{
> + riscv_override_options_internal (opts);
> +}
> +
> +static GTY (()) tree riscv_previous_fndecl;
> +
> /* Implement TARGET_CONDITIONAL_REGISTER_USAGE. */
>
> static void
> @@ -8505,7 +8574,12 @@ riscv_get_interrupt_type (tree decl)
> return MACHINE_MODE;
> }
>
> -/* Implement `TARGET_SET_CURRENT_FUNCTION'. */
> +/* Implement `TARGET_SET_CURRENT_FUNCTION'. Unpack the codegen decisions
> + like tuning and ISA features from the DECL_FUNCTION_SPECIFIC_TARGET
> + of the function, if such exists. This function may be called multiple
> + times on a single function so use aarch64_previous_fndecl to avoid
> + setting up identical state. */
> +
> /* Sanity cheching for above function attributes. */
> static void
> riscv_set_current_function (tree decl)
> @@ -8513,36 +8587,66 @@ riscv_set_current_function (tree decl)
> if (decl == NULL_TREE
> || current_function_decl == NULL_TREE
> || current_function_decl == error_mark_node
> - || ! cfun->machine
> - || cfun->machine->attributes_checked_p)
> + || ! cfun->machine)
> return;
>
> - cfun->machine->naked_p = riscv_naked_function_p (decl);
> - cfun->machine->interrupt_handler_p
> - = riscv_interrupt_type_p (TREE_TYPE (decl));
> + if (!cfun->machine->attributes_checked_p)
> + {
> + cfun->machine->naked_p = riscv_naked_function_p (decl);
> + cfun->machine->interrupt_handler_p
> + = riscv_interrupt_type_p (TREE_TYPE (decl));
>
> - if (cfun->machine->naked_p && cfun->machine->interrupt_handler_p)
> - error ("function attributes %qs and %qs are mutually exclusive",
> - "interrupt", "naked");
> + if (cfun->machine->naked_p && cfun->machine->interrupt_handler_p)
> + error ("function attributes %qs and %qs are mutually exclusive",
> + "interrupt", "naked");
>
> - if (cfun->machine->interrupt_handler_p)
> - {
> - tree ret = TREE_TYPE (TREE_TYPE (decl));
> - tree args = TYPE_ARG_TYPES (TREE_TYPE (decl));
> + if (cfun->machine->interrupt_handler_p)
> + {
> + tree ret = TREE_TYPE (TREE_TYPE (decl));
> + tree args = TYPE_ARG_TYPES (TREE_TYPE (decl));
> +
> + if (TREE_CODE (ret) != VOID_TYPE)
> + error ("%qs function cannot return a value", "interrupt");
>
> - if (TREE_CODE (ret) != VOID_TYPE)
> - error ("%qs function cannot return a value", "interrupt");
> + if (args && TREE_CODE (TREE_VALUE (args)) != VOID_TYPE)
> + error ("%qs function cannot have arguments", "interrupt");
>
> - if (args && TREE_CODE (TREE_VALUE (args)) != VOID_TYPE)
> - error ("%qs function cannot have arguments", "interrupt");
> + cfun->machine->interrupt_mode = riscv_get_interrupt_type (decl);
>
> - cfun->machine->interrupt_mode = riscv_get_interrupt_type (decl);
> + gcc_assert (cfun->machine->interrupt_mode != UNKNOWN_MODE);
> + }
>
> - gcc_assert (cfun->machine->interrupt_mode != UNKNOWN_MODE);
> + /* Don't print the above diagnostics more than once. */
> + cfun->machine->attributes_checked_p = 1;
> }
>
> - /* Don't print the above diagnostics more than once. */
> - cfun->machine->attributes_checked_p = 1;
> + if (!decl || decl == riscv_previous_fndecl)
> + return;
> +
> + tree old_tree = (riscv_previous_fndecl
> + ? DECL_FUNCTION_SPECIFIC_TARGET (riscv_previous_fndecl)
> + : NULL_TREE);
> +
> + tree new_tree = DECL_FUNCTION_SPECIFIC_TARGET (decl);
> +
> + /* If current function has no attributes but the previous one did,
> + use the default node. */
> + if (!new_tree && old_tree)
> + new_tree = target_option_default_node;
> +
> + /* If nothing to do, return. #pragma GCC reset or #pragma GCC pop to
> + the default have been handled by aarch64_save_restore_target_globals from
> + aarch64_pragma_target_parse. */
> + if (old_tree == new_tree)
> + return;
> +
> + riscv_previous_fndecl = decl;
> +
> + /* First set the target options. */
> + cl_target_option_restore (&global_options, &global_options_set,
> + TREE_TARGET_OPTION (new_tree));
> +
> + riscv_save_restore_target_globals (new_tree);
> }
>
> /* Implement TARGET_MERGE_DECL_ATTRIBUTES. */
> @@ -9664,6 +9768,12 @@ riscv_preferred_else_value (unsigned ifn, tree vectype, unsigned int nops,
> #undef TARGET_OPTION_OVERRIDE
> #define TARGET_OPTION_OVERRIDE riscv_option_override
>
> +#undef TARGET_OPTION_RESTORE
> +#define TARGET_OPTION_RESTORE riscv_option_restore
> +
> +#undef TARGET_OPTION_VALID_ATTRIBUTE_P
> +#define TARGET_OPTION_VALID_ATTRIBUTE_P riscv_option_valid_attribute_p
> +
> #undef TARGET_LEGITIMIZE_ADDRESS
> #define TARGET_LEGITIMIZE_ADDRESS riscv_legitimize_address
>
> diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
> index 1e9813b4f39..6205d7533f4 100644
> --- a/gcc/config/riscv/riscv.h
> +++ b/gcc/config/riscv/riscv.h
> @@ -25,6 +25,8 @@ along with GCC; see the file COPYING3. If not see
> #include <stdbool.h>
> #include "config/riscv/riscv-opts.h"
>
> +#define SWITCHABLE_TARGET 1
> +
> /* Target CPU builtins. */
> #define TARGET_CPU_CPP_BUILTINS() riscv_cpu_cpp_builtins (pfile)
>
> @@ -1056,6 +1058,10 @@ while (0)
> #define ASM_DECLARE_FUNCTION_NAME(STR, NAME, DECL) \
> riscv_declare_function_name (STR, NAME, DECL)
>
> +#undef ASM_DECLARE_FUNCTION_SIZE
> +#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \
> + riscv_declare_function_size (FILE, FNAME, DECL)
> +
> /* Add output .variant_cc directive for specific alias definition. */
> #undef ASM_OUTPUT_DEF_FROM_DECLS
> #define ASM_OUTPUT_DEF_FROM_DECLS(STR, DECL, TARGET) \
> diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
> index 70d78151cee..1bd661a3fe4 100644
> --- a/gcc/config/riscv/riscv.opt
> +++ b/gcc/config/riscv/riscv.opt
> @@ -84,11 +84,11 @@ Target RejectNegative Joined Negative(march=)
> lower-case.
>
> mtune=
> -Target RejectNegative Joined Var(riscv_tune_string)
> +Target RejectNegative Joined Var(riscv_tune_string) Save
> -mtune=PROCESSOR Optimize the output for PROCESSOR.
>
> mcpu=
> -Target RejectNegative Joined Var(riscv_cpu_string)
> +Target RejectNegative Joined Var(riscv_cpu_string) Save
> -mcpu=PROCESSOR Use architecture of and optimize the output for PROCESSOR.
>
> msmall-data-limit=
> @@ -106,7 +106,7 @@ memory accesses to be generated as compressed instructions. Currently targets
> 32-bit integer load/stores.
>
> mcmodel=
> -Target RejectNegative Joined Enum(code_model) Var(riscv_cmodel) Init(TARGET_DEFAULT_CMODEL)
> +Target RejectNegative Joined Enum(code_model) Var(riscv_cmodel) Init(TARGET_DEFAULT_CMODEL) Save
> Specify the code model.
>
> mstrict-align
> diff --git a/gcc/config/riscv/t-riscv b/gcc/config/riscv/t-riscv
> index 95becfc819b..3b9686daa58 100644
> --- a/gcc/config/riscv/t-riscv
> +++ b/gcc/config/riscv/t-riscv
> @@ -115,6 +115,11 @@ riscv-v.o: $(srcdir)/config/riscv/riscv-v.cc \
> $(COMPILE) $<
> $(POSTCOMPILE)
>
> +riscv-target-attr.o: $(srcdir)/config/riscv/riscv-target-attr.cc $(CONFIG_H) \
> + $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(DIAGNOSTIC_CORE_H)
> + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
> + $(srcdir)/config/riscv/riscv-target-attr.cc
> +
> thead.o: $(srcdir)/config/riscv/thead.cc \
> $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TARGET_H) backend.h $(RTL_H) \
> memmodel.h $(EMIT_RTL_H) poly-int.h output.h
> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> index 7cdfdf8c83b..856dd93d16a 100644
> --- a/gcc/doc/extend.texi
> +++ b/gcc/doc/extend.texi
> @@ -6295,8 +6295,66 @@ void f (void) __attribute__ ((interrupt ("user")));
> Permissible values for this parameter are @code{user}, @code{supervisor},
> and @code{machine}. If there is no parameter, then it defaults to
> @code{machine}.
> +
> +@end table
> +
> +The following target-specific function attributes are available for the
> +RISC-V target. For the most part, these options mirror the behavior of
> +similar command-line options (@pxref{RISC-V Options}), but on a
> +per-function basis.
> +
> +@table @code
> +@cindex @code{arch=} function attribute, RISC-V
> +@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, in addtion, it also support
> +extension enablement list, a list of extension name and prefixed with @code{+},
> +like @code{arch=+zba} means enable @code{zba} extension.
> +Multiple extension can be enabled by separating them with a comma. For example:
> +@code{arch=+zba,+zbb}.
> +
> +@cindex @code{tune=} function attribute, RISC-V
> +@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{cpu=} function attribute, RISC-V
> +@item cpu=
> +Specifies the core for which to tune the performance of this function and also
> +whose architectural features to use. The behavior and valid arguments are the
> +same as for the @option{-mcpu=} command-line option.
> +
> @end table
>
> +The above target attributes can be specified as follows:
> +
> +@smallexample
> +__attribute__((target("@var{attr-string}")))
> +int
> +f (int a)
> +@{
> + return a + 5;
> +@}
> +@end smallexample
> +
> +where @code{@var{attr-string}} is one of the attribute strings specified above.
> +
> +Multiple target function attributes can be specified by separating them with
> +a semicolon. For example:
> +@smallexample
> +__attribute__((target("arch=+zba,+zbb;tune=rocket")))
> +int
> +foo (int a)
> +@{
> + return a + 5;
> +@}
> +@end smallexample
> +
> +is valid and compiles function @code{foo} with @code{zba}
> +and @code{zbb} extensions and tunes it for @code{rocket}.
> +
> @node RL78 Function Attributes
> @subsection RL78 Function Attributes
>
> diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-01.c b/gcc/testsuite/gcc.target/riscv/target-attr-01.c
> new file mode 100644
> index 00000000000..b3f3d65d543
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/target-attr-01.c
> @@ -0,0 +1,31 @@
> +/* { dg-do compile } */
> +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> +/* { dg-final { check-function-bodies "**" "" } } */
> +
> +
> +/*
> +** foo:
> +** ...
> +** sh1add\s*a0,a1,a0
> +** ...
> +*/
> +
> +
> +long foo() __attribute__((target("arch=rv64gc_zba")));
> +long foo(long a, long b){
> + return a + (b * 2);
> +}
> +
> +/*
> +** bar:
> +** ...
> +** slli\s*a1,a1,1
> +** add\s*a0,a1,a0
> +** ...
> +*/
> +
> +
> +long bar(long a, long b){
> + return a + (b * 2);
> +}
> diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-02.c b/gcc/testsuite/gcc.target/riscv/target-attr-02.c
> new file mode 100644
> index 00000000000..c010089a823
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/target-attr-02.c
> @@ -0,0 +1,31 @@
> +/* { dg-do compile } */
> +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> +/* { dg-final { check-function-bodies "**" "" } } */
> +
> +
> +/*
> +** foo:
> +** ...
> +** sh1add\s*a0,a1,a0
> +** ...
> +*/
> +
> +
> +long foo() __attribute__((target("arch=+zba")));
> +long foo(long a, long b){
> + return a + (b * 2);
> +}
> +
> +/*
> +** bar:
> +** ...
> +** slli\s*a1,a1,1
> +** add\s*a0,a1,a0
> +** ...
> +*/
> +
> +
> +long bar(long a, long b){
> + return a + (b * 2);
> +}
> diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-03.c b/gcc/testsuite/gcc.target/riscv/target-attr-03.c
> new file mode 100644
> index 00000000000..b4896cb2e27
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/target-attr-03.c
> @@ -0,0 +1,26 @@
> +/* { dg-do compile } */
> +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> +/* { dg-options "-march=rv64gc_zba -O2 -mabi=lp64" } */
> +/* { dg-final { check-function-bodies "**" "" } } */
> +
> +/*
> +** foo:
> +** ...
> +** slli\s*a1,a1,1
> +** add\s*a0,a1,a0
> +** ...
> +*/
> +long foo() __attribute__((target("arch=rv64gc")));
> +long foo(long a, long b){
> + return a + (b * 2);
> +}
> +
> +/*
> +** bar:
> +** ...
> +** sh1add\s*a0,a1,a0
> +** ...
> +*/
> +long bar(long a, long b){
> + return a + (b * 2);
> +}
> diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-04.c b/gcc/testsuite/gcc.target/riscv/target-attr-04.c
> new file mode 100644
> index 00000000000..369d6514e5a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/target-attr-04.c
> @@ -0,0 +1,28 @@
> +/* { dg-do compile } */
> +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> +/* { dg-options "-march=rv64gc_zba -O2 -mabi=lp64 -mtune=rocket" } */
> +/* { dg-final { check-function-bodies "**" "" } } */
> +
> +/*
> +** foo:
> +** ...
> +** # tune = sifive-7-series
> +** ...
> +** slli\s*a1,a1,1
> +** add\s*a0,a1,a0
> +** ...
> +*/
> +long foo() __attribute__((target("cpu=sifive-u74")));
> +long foo(long a, long b){
> + return a + (b * 2);
> +}
> +
> +/*
> +** bar:
> +** ...
> +** sh1add\s*a0,a1,a0
> +** ...
> +*/
> +long bar(long a, long b){
> + return a + (b * 2);
> +}
> diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-05.c b/gcc/testsuite/gcc.target/riscv/target-attr-05.c
> new file mode 100644
> index 00000000000..c75368dcebf
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/target-attr-05.c
> @@ -0,0 +1,27 @@
> +/* { dg-do compile } */
> +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> +/* { dg-options "-march=rv64gc_zba -O2 -mabi=lp64 -mtune=rocket" } */
> +/* { dg-final { check-function-bodies "**" "" } } */
> +
> +/*
> +** foo:
> +** ...
> +** # tune = sifive-7-series
> +** ...
> +** sh1add\s*a0,a1,a0
> +** ...
> +*/
> +long foo() __attribute__((target("cpu=sifive-u74;arch=rv64gc_zba")));
> +long foo(long a, long b){
> + return a + (b * 2);
> +}
> +
> +/*
> +** bar:
> +** ...
> +** sh1add\s*a0,a1,a0
> +** ...
> +*/
> +long bar(long a, long b){
> + return a + (b * 2);
> +}
> diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-06.c b/gcc/testsuite/gcc.target/riscv/target-attr-06.c
> new file mode 100644
> index 00000000000..369c95eeb54
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/target-attr-06.c
> @@ -0,0 +1,27 @@
> +/* { dg-do compile } */
> +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> +/* { dg-options "-march=rv64gc_zba -O2 -mabi=lp64 -mtune=rocket" } */
> +/* { dg-final { check-function-bodies "**" "" } } */
> +
> +/*
> +** foo:
> +** ...
> +** # tune = sifive-5-series
> +** ...
> +** sh1add\s*a0,a1,a0
> +** ...
> +*/
> +long foo() __attribute__((target("cpu=sifive-u74;tune=sifive-5-series;arch=rv64gc_zba")));
> +long foo(long a, long b){
> + return a + (b * 2);
> +}
> +
> +/*
> +** bar:
> +** ...
> +** sh1add\s*a0,a1,a0
> +** ...
> +*/
> +long bar(long a, long b){
> + return a + (b * 2);
> +}
> diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-07.c b/gcc/testsuite/gcc.target/riscv/target-attr-07.c
> new file mode 100644
> index 00000000000..4ff81166a62
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/target-attr-07.c
> @@ -0,0 +1,25 @@
> +/* { dg-do compile } */
> +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> +/* { dg-options "-march=rv64gc_zba -O2 -mabi=lp64 -mtune=rocket" } */
> +/* { dg-final { check-function-bodies "**" "" } } */
> +
> +/*
> +** foo:
> +** ...
> +** # tune = sifive-5-series
> +** ...
> +*/
> +long foo() __attribute__((target("tune=sifive-5-series")));
> +long foo(long a, long b){
> + return a + (b * 2);
> +}
> +
> +/*
> +** bar:
> +** ...
> +** sh1add\s*a0,a1,a0
> +** ...
> +*/
> +long bar(long a, long b){
> + return a + (b * 2);
> +}
> diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-01.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-01.c
> new file mode 100644
> index 00000000000..91cbcaac21d
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-01.c
> @@ -0,0 +1,13 @@
> +/* { dg-do compile } */
> +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> +
> +
> +long foo() __attribute__((target("arch=rv64gc_zba;;"))); /* { dg-error "malformed" } */
> +long foo(long a, long b){
> + return a + (b * 2);
> +}
> +
> +long bar(long a, long b){
> + return a + (b * 2);
> +}
> diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-02.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-02.c
> new file mode 100644
> index 00000000000..0c838bb3ca7
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-02.c
> @@ -0,0 +1,13 @@
> +/* { dg-do compile } */
> +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> +
> +
> +long foo() __attribute__((target("cpu=xyz-cpu"))); /* { dg-error "unknown CPU" } */
> +long foo(long a, long b){
> + return a + (b * 2);
> +}
> +
> +long bar(long a, long b){
> + return a + (b * 2);
> +}
> diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-03.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-03.c
> new file mode 100644
> index 00000000000..09702d1690a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-03.c
> @@ -0,0 +1,13 @@
> +/* { dg-do compile } */
> +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> +
> +
> +long foo() __attribute__((target("tune=xyz-cpu"))); /* { dg-error "unknown TUNE" } */
> +long foo(long a, long b){
> + return a + (b * 2);
> +}
> +
> +long bar(long a, long b){
> + return a + (b * 2);
> +}
> diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-04.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-04.c
> new file mode 100644
> index 00000000000..1d9a0ffdd88
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-04.c
> @@ -0,0 +1,13 @@
> +/* { dg-do compile } */
> +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> +
> +
> +long foo() __attribute__((target(123))); /* { dg-error "argument not a string" } */
> +long foo(long a, long b){
> + return a + (b * 2);
> +}
> +
> +long bar(long a, long b){
> + return a + (b * 2);
> +}
> diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-05.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-05.c
> new file mode 100644
> index 00000000000..24a81c5279b
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-05.c
> @@ -0,0 +1,13 @@
> +/* { dg-do compile } */
> +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> +
> +
> +long foo() __attribute__((target(""))); /* { dg-warning "empty string in attribute .target." } */
> +long foo(long a, long b){
> + return a + (b * 2);
> +}
> +
> +long bar(long a, long b){
> + return a + (b * 2);
> +}
> diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-06.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-06.c
> new file mode 100644
> index 00000000000..a0d65859d40
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-06.c
> @@ -0,0 +1,13 @@
> +/* { dg-do compile } */
> +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> +
> +
> +long foo() __attribute__((target("arch=*x"))); /* { dg-error "must start with \\+ or rv" } */
> +long foo(long a, long b){
> + return a + (b * 2);
> +}
> +
> +long bar(long a, long b){
> + return a + (b * 2);
> +}
> diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-07.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-07.c
> new file mode 100644
> index 00000000000..8aa82504dc1
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-07.c
> @@ -0,0 +1,13 @@
> +/* { dg-do compile } */
> +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> +
> +
> +long foo() __attribute__((target("arch=+zbb_zba"))); /* { dg-error "extension 'zbb_zba' starts with 'z' but is unsupported standard extension" } */
> +long foo(long a, long b){
> + return a + (b * 2);
> +}
> +
> +long bar(long a, long b){
> + return a + (b * 2);
> +}
> diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-08.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-08.c
> new file mode 100644
> index 00000000000..68d211de887
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-08.c
> @@ -0,0 +1,8 @@
> +/* { dg-do compile } */
> +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> +
> +long foo() __attribute__((target("arch=rv64gc_zba;arch=rv64gc_zba"))); /* { dg-error "arch appears more than once" } */
> +long foo(long a, long b){
> + return a + (b * 2);
> +}
> diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-09.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-09.c
> new file mode 100644
> index 00000000000..2b6e4982894
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-09.c
> @@ -0,0 +1,8 @@
> +/* { dg-do compile } */
> +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> +
> +long foo() __attribute__((target("cpu=sifive-u74;cpu=sifive-u74"))); /* { dg-error "cpu appears more than once" } */
> +long foo(long a, long b){
> + return a + (b * 2);
> +}
> diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-10.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-10.c
> new file mode 100644
> index 00000000000..00cefa03e41
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-10.c
> @@ -0,0 +1,8 @@
> +/* { dg-do compile } */
> +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> +
> +long foo() __attribute__((target("tune=sifive-u74;tune=sifive-u74"))); /* { dg-error "tune appears more than once" } */
> +long foo(long a, long b){
> + return a + (b * 2);
> +}
> --
> 2.40.1
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2] RISC-V: Implement target attribute
2023-11-15 23:58 ` Christoph Müllner
@ 2023-11-16 11:40 ` Kito Cheng
0 siblings, 0 replies; 6+ messages in thread
From: Kito Cheng @ 2023-11-16 11:40 UTC (permalink / raw)
To: Christoph Müllner; +Cc: Kito Cheng, gcc-patches, palmer, jeffreyalaw
Committed with changelog update :P Thanks for the review.
On Thu, Nov 16, 2023 at 7:59 AM Christoph Müllner
<christoph.muellner@vrull.eu> wrote:
>
> On Tue, Nov 14, 2023 at 3:15 PM Kito Cheng <kito.cheng@sifive.com> wrote:
> >
> > The target attribute which proposed in [1], target attribute allow user
> > to specify a local setting per-function basis.
> >
> > The syntax of target attribute is `__attribute__((target("<ATTR-STRING>")))`.
> >
> > and the syntax of `<ATTR-STRING>` describes below:
> > ```
> > ATTR-STRING := ATTR-STRING ';' ATTR
> > | ATTR
> >
> > ATTR := ARCH-ATTR
> > | CPU-ATTR
> > | TUNE-ATTR
> >
> > ARCH-ATTR := 'arch=' EXTENSIONS-OR-FULLARCH
> >
> > EXTENSIONS-OR-FULLARCH := <EXTENSIONS>
> > | <FULLARCHSTR>
> >
> > EXTENSIONS := <EXTENSION> ',' <EXTENSIONS>
> > | <EXTENSION>
> >
> > FULLARCHSTR := <full-arch-string>
> >
> > EXTENSION := <OP> <EXTENSION-NAME> <VERSION>
> >
> > OP := '+'
> >
> > VERSION := [0-9]+ 'p' [0-9]+
> > | [1-9][0-9]*
> > |
> >
> > EXTENSION-NAME := Naming rule is defined in RISC-V ISA manual
> >
> > CPU-ATTR := 'cpu=' <valid-cpu-name>
> > TUNE-ATTR := 'tune=' <valid-tune-name>
> > ```
> >
> > Changes since v1:
> > - Use std::unique_ptr rather than alloca to prevent memory issue.
> > - Error rather than warning when attribute duplicated.
> >
> > [1] https://github.com/riscv-non-isa/riscv-c-api-doc/pull/35
>
> I've reviewed with a focus on the utilized backend hooks and macros.
>
> Reviewed-by: Christoph Müllner <christoph.muellner@vrull.eu>
>
> Note, that in the changelog below there are quite many empty entries.
>
> >
> > gcc/ChangeLog:
> >
> > * config.gcc (riscv): Add riscv-target-attr.o.
> > * config/riscv/riscv-protos.h (riscv_declare_function_size) New.
> > (riscv_option_valid_attribute_p): New.
> > (riscv_override_options_internal): New.
> > (struct riscv_tune_info): New.
> > (riscv_parse_tune): New.
> > * config/riscv/riscv-target-attr.cc
> > (class riscv_target_attr_parser): New.
> > (struct riscv_attribute_info): New.
> > (riscv_attributes): New.
> > (riscv_target_attr_parser::parse_arch):
> > (riscv_target_attr_parser::handle_arch):
> > (riscv_target_attr_parser::handle_cpu):
> > (riscv_target_attr_parser::handle_tune):
> > (riscv_target_attr_parser::update_settings):
> > (riscv_process_one_target_attr):
> > (num_occurences_in_str):
> > (riscv_process_target_attr):
> > (riscv_option_valid_attribute_p):
> > * config/riscv/riscv.cc: Include target-globals.h and
> > riscv-subset.h.
> > (struct riscv_tune_info): Move to riscv-protos.h.
> > (get_tune_str):
> > (riscv_parse_tune):
> > (riscv_declare_function_size):
> > (riscv_option_override): Build target_option_default_node and
> > target_option_current_node.
> > (riscv_save_restore_target_globals):
> > (riscv_option_restore):
> > (riscv_previous_fndecl):
> > (riscv_set_current_function): Apply the target attribute.
> > (TARGET_OPTION_RESTORE): Define.
> > (TARGET_OPTION_VALID_ATTRIBUTE_P): Ditto.
> > * config/riscv/riscv.h (SWITCHABLE_TARGET): Define to 1.
> > (ASM_DECLARE_FUNCTION_SIZE) Define.
> > * config/riscv/riscv.opt (mtune=): Add Save attribute.
> > (mcpu=): Ditto.
> > (mcmodel=): Ditto.
> > * config/riscv/t-riscv: Add build rule for riscv-target-attr.o
> > * doc/extend.texi: Add doc for target attribute.
> >
> > gcc/testsuite/ChangeLog:
> >
> > * gcc.target/riscv/target-attr-01.c: New.
> > * gcc.target/riscv/target-attr-02.c: Ditto.
> > * gcc.target/riscv/target-attr-03.c: Ditto.
> > * gcc.target/riscv/target-attr-04.c: Ditto.
> > * gcc.target/riscv/target-attr-05.c: Ditto.
> > * gcc.target/riscv/target-attr-06.c: Ditto.
> > * gcc.target/riscv/target-attr-07.c: Ditto.
> > * gcc.target/riscv/target-attr-bad-01.c: Ditto.
> > * gcc.target/riscv/target-attr-bad-02.c: Ditto.
> > * gcc.target/riscv/target-attr-bad-03.c: Ditto.
> > * gcc.target/riscv/target-attr-bad-04.c: Ditto.
> > * gcc.target/riscv/target-attr-bad-05.c: Ditto.
> > * gcc.target/riscv/target-attr-bad-06.c: Ditto.
> > * gcc.target/riscv/target-attr-bad-07.c: Ditto.
> > * gcc.target/riscv/target-attr-bad-08.c: Ditto.
> > * gcc.target/riscv/target-attr-bad-09.c: Ditto.
> > * gcc.target/riscv/target-attr-bad-10.c: Ditto.
> > ---
> > gcc/config.gcc | 2 +-
> > gcc/config/riscv/riscv-protos.h | 21 +
> > gcc/config/riscv/riscv-target-attr.cc | 395 ++++++++++++++++++
> > gcc/config/riscv/riscv.cc | 192 +++++++--
> > gcc/config/riscv/riscv.h | 6 +
> > gcc/config/riscv/riscv.opt | 6 +-
> > gcc/config/riscv/t-riscv | 5 +
> > gcc/doc/extend.texi | 58 +++
> > .../gcc.target/riscv/target-attr-01.c | 31 ++
> > .../gcc.target/riscv/target-attr-02.c | 31 ++
> > .../gcc.target/riscv/target-attr-03.c | 26 ++
> > .../gcc.target/riscv/target-attr-04.c | 28 ++
> > .../gcc.target/riscv/target-attr-05.c | 27 ++
> > .../gcc.target/riscv/target-attr-06.c | 27 ++
> > .../gcc.target/riscv/target-attr-07.c | 25 ++
> > .../gcc.target/riscv/target-attr-bad-01.c | 13 +
> > .../gcc.target/riscv/target-attr-bad-02.c | 13 +
> > .../gcc.target/riscv/target-attr-bad-03.c | 13 +
> > .../gcc.target/riscv/target-attr-bad-04.c | 13 +
> > .../gcc.target/riscv/target-attr-bad-05.c | 13 +
> > .../gcc.target/riscv/target-attr-bad-06.c | 13 +
> > .../gcc.target/riscv/target-attr-bad-07.c | 13 +
> > .../gcc.target/riscv/target-attr-bad-08.c | 8 +
> > .../gcc.target/riscv/target-attr-bad-09.c | 8 +
> > .../gcc.target/riscv/target-attr-bad-10.c | 8 +
> > 25 files changed, 950 insertions(+), 45 deletions(-)
> > create mode 100644 gcc/config/riscv/riscv-target-attr.cc
> > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-01.c
> > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-02.c
> > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-03.c
> > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-04.c
> > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-05.c
> > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-06.c
> > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-07.c
> > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-01.c
> > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-02.c
> > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-03.c
> > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-04.c
> > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-05.c
> > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-06.c
> > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-07.c
> > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-08.c
> > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-09.c
> > create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-10.c
> >
> > diff --git a/gcc/config.gcc b/gcc/config.gcc
> > index ba6d63e33ac..0e86e60629e 100644
> > --- a/gcc/config.gcc
> > +++ b/gcc/config.gcc
> > @@ -546,7 +546,7 @@ riscv*)
> > extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o riscv-selftests.o riscv-string.o"
> > extra_objs="${extra_objs} riscv-v.o riscv-vsetvl.o riscv-vector-costs.o riscv-avlprop.o"
> > extra_objs="${extra_objs} riscv-vector-builtins.o riscv-vector-builtins-shapes.o riscv-vector-builtins-bases.o"
> > - extra_objs="${extra_objs} thead.o"
> > + extra_objs="${extra_objs} thead.o riscv-target-attr.o"
> > d_target_objs="riscv-d.o"
> > extra_headers="riscv_vector.h"
> > target_gtfiles="$target_gtfiles \$(srcdir)/config/riscv/riscv-vector-builtins.cc"
> > diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
> > index 8cdfadbcf10..196b53f10f3 100644
> > --- a/gcc/config/riscv/riscv-protos.h
> > +++ b/gcc/config/riscv/riscv-protos.h
> > @@ -124,6 +124,7 @@ extern void riscv_split_doubleword_move (rtx, rtx);
> > extern const char *riscv_output_move (rtx, rtx);
> > extern const char *riscv_output_return ();
> > extern void riscv_declare_function_name (FILE *, const char *, tree);
> > +extern void riscv_declare_function_size (FILE *, const char *, tree);
> > extern void riscv_asm_output_alias (FILE *, const tree, const tree);
> > extern void riscv_asm_output_external (FILE *, const tree, const char *);
> > extern bool
> > @@ -647,5 +648,25 @@ extern bool th_print_operand_address (FILE *, machine_mode, rtx);
> >
> > extern bool riscv_use_divmod_expander (void);
> > void riscv_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int);
> > +extern bool
> > +riscv_option_valid_attribute_p (tree, tree, tree, int);
> > +extern void
> > +riscv_override_options_internal (struct gcc_options *);
> > +
> > +struct riscv_tune_param;
> > +/* Information about one micro-arch we know about. */
> > +struct riscv_tune_info {
> > + /* This micro-arch canonical name. */
> > + const char *name;
> > +
> > + /* Which automaton to use for tuning. */
> > + enum riscv_microarchitecture_type microarchitecture;
> > +
> > + /* Tuning parameters for this micro-arch. */
> > + const struct riscv_tune_param *tune_param;
> > +};
> > +
> > +const struct riscv_tune_info *
> > +riscv_parse_tune (const char *, bool);
> >
> > #endif /* ! GCC_RISCV_PROTOS_H */
> > diff --git a/gcc/config/riscv/riscv-target-attr.cc b/gcc/config/riscv/riscv-target-attr.cc
> > new file mode 100644
> > index 00000000000..78f259d0c96
> > --- /dev/null
> > +++ b/gcc/config/riscv/riscv-target-attr.cc
> > @@ -0,0 +1,395 @@
> > +/* Subroutines used for parsing target attribute for RISC-V.
> > + Copyright (C) 2023 Free Software Foundation, Inc.
> > +
> > +This file is part of GCC.
> > +
> > +GCC is free software; you can redistribute it and/or modify
> > +it under the terms of the GNU General Public License as published by
> > +the Free Software Foundation; either version 3, or (at your option)
> > +any later version.
> > +
> > +GCC is distributed in the hope that it will be useful,
> > +but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > +GNU General Public License for more details.
> > +
> > +You should have received a copy of the GNU General Public License
> > +along with GCC; see the file COPYING3. If not see
> > +<http://www.gnu.org/licenses/>. */
> > +
> > +#define IN_TARGET_CODE 1
> > +
> > +#define INCLUDE_MEMORY
> > +#define INCLUDE_STRING
> > +#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"
> > +#include "riscv-subset.h"
> > +
> > +namespace {
> > +class riscv_target_attr_parser
> > +{
> > +public:
> > + riscv_target_attr_parser (location_t loc)
> > + : m_found_arch_p (false)
> > + , m_found_tune_p (false)
> > + , m_found_cpu_p (false)
> > + , m_subset_list (nullptr)
> > + , m_loc (loc)
> > + , m_cpu_info (nullptr)
> > + , m_tune (nullptr)
> > + {
> > + }
> > +
> > + bool handle_arch (const char *);
> > + bool handle_cpu (const char *);
> > + bool handle_tune (const char *);
> > +
> > + void set_loc (location_t loc) {
> > + m_loc = loc;
> > + }
> > +
> > + void update_settings (struct gcc_options *opts) const;
> > +private:
> > + const char *m_raw_attr_str;
> > + bool parse_arch (const char *);
> > +
> > + bool m_found_arch_p;
> > + bool m_found_tune_p;
> > + bool m_found_cpu_p;
> > + riscv_subset_list *m_subset_list;
> > + location_t m_loc;
> > + const riscv_cpu_info *m_cpu_info;
> > + const char *m_tune;
> > +};
> > +}
> > +
> > +/* All the information needed to handle a target attribute.
> > + NAME is the name of the attribute.
> > + HANDLER is the function that takes the attribute string as an argument. */
> > +
> > +struct riscv_attribute_info
> > +{
> > + const char *name;
> > + bool (riscv_target_attr_parser::*handler) (const char *);
> > +};
> > +
> > +/* The target attributes that we support. */
> > +
> > +static const struct riscv_attribute_info riscv_attributes[]
> > + = {{"arch", &riscv_target_attr_parser::handle_arch},
> > + {"cpu", &riscv_target_attr_parser::handle_cpu},
> > + {"tune", &riscv_target_attr_parser::handle_tune}};
> > +
> > +bool
> > +riscv_target_attr_parser::parse_arch (const char *str)
> > +{
> > + if (m_subset_list)
> > + delete m_subset_list;
> > + /* Check if it's setting full arch string. */
> > + if (strncmp ("rv", str, strlen ("rv")) == 0)
> > + {
> > + m_subset_list = riscv_subset_list::parse (str, location_t ());
> > +
> > + if (m_subset_list == nullptr)
> > + goto fail;
> > +
> > + return true;
> > + }
> > + else
> > + {
> > + /* Parsing the extension list like "+<ext>[,+<ext>]*". */
> > + size_t len = strlen (str);
> > + std::unique_ptr<char> buf (new char[len]);
> > + char *str_to_check = buf.get ();
> > + strcpy (str_to_check, str);
> > + const char *token = strtok_r (str_to_check, ",", &str_to_check);
> > + m_subset_list = riscv_current_subset_list ()->clone ();
> > + m_subset_list->set_loc (m_loc);
> > + while (token)
> > + {
> > + if (token[0] != '+')
> > + {
> > + error_at (
> > + m_loc,
> > + "unexpected arch for %<target()%> attribute: must start "
> > + "with + or rv");
> > + goto fail;
> > + }
> > + else
> > + {
> > + const char *result = m_subset_list->parse_single_ext (token + 1);
> > + /* Check parse_single_ext has consume all string. */
> > + if (*result != '\0')
> > + {
> > + error_at (
> > + m_loc,
> > + "unexpected arch for %<target()%> attribute: bad "
> > + "string found %<%s%>", token);
> > + goto fail;
> > + }
> > + }
> > + token = strtok_r (NULL, ",", &str_to_check);
> > + }
> > + return true;
> > + }
> > +fail:
> > + if (m_subset_list != nullptr)
> > + {
> > + delete m_subset_list;
> > + m_subset_list = nullptr;
> > + }
> > + return false;
> > +}
> > +
> > +/* Handle the ARCH_STR argument to the arch= target attribute. */
> > +
> > +bool
> > +riscv_target_attr_parser::handle_arch (const char *str)
> > +{
> > + if (m_found_arch_p)
> > + error_at (m_loc, "%<target()%> attribute: arch appears more than once");
> > + m_found_arch_p = true;
> > + return parse_arch (str);
> > +}
> > +
> > +/* Handle the CPU_STR argument to the cpu= target attribute. */
> > +
> > +bool
> > +riscv_target_attr_parser::handle_cpu (const char *str)
> > +{
> > + if (m_found_cpu_p)
> > + error_at (m_loc, "%<target()%> attribute: cpu appears more than once");
> > +
> > + m_found_cpu_p = true;
> > + const riscv_cpu_info *cpu_info = riscv_find_cpu (str);
> > +
> > + if (!cpu_info)
> > + {
> > + error_at (m_loc, "%<target()%> attribute: unknown CPU %qs", str);
> > + return false;
> > + }
> > +
> > + if (m_subset_list == nullptr)
> > + {
> > + const char *arch_str = cpu_info->arch;
> > + m_subset_list = riscv_subset_list::parse (arch_str, m_loc);
> > + gcc_assert (m_subset_list);
> > + }
> > +
> > + m_cpu_info = cpu_info;
> > + return true;
> > +}
> > +
> > +/* Handle the TUNE_STR argument to the tune= target attribute. */
> > +
> > +bool
> > +riscv_target_attr_parser::handle_tune (const char *str)
> > +{
> > + if (m_found_tune_p)
> > + error_at (m_loc, "%<target()%> attribute: tune appears more than once");
> > + m_found_tune_p = true;
> > + const struct riscv_tune_info *tune = riscv_parse_tune (str, true);
> > +
> > + if (tune == nullptr)
> > + {
> > + error_at (m_loc, "%<target()%> attribute: unknown TUNE %qs", str);
> > + return false;
> > + }
> > +
> > + m_tune = tune->name;
> > +
> > + return true;
> > +}
> > +
> > +void
> > +riscv_target_attr_parser::update_settings (struct gcc_options *opts) const
> > +{
> > + if (m_subset_list)
> > + riscv_set_arch_by_subset_list (m_subset_list, opts);
> > +
> > + if (m_cpu_info)
> > + opts->x_riscv_cpu_string = m_cpu_info->name;
> > +
> > + if (m_tune)
> > + opts->x_riscv_tune_string = m_tune;
> > + else
> > + {
> > + if (m_cpu_info)
> > + opts->x_riscv_tune_string = m_cpu_info->tune;
> > + }
> > +}
> > +
> > +/* 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
> > +riscv_process_one_target_attr (char *arg_str,
> > + location_t loc,
> > + riscv_target_attr_parser &attr_parser)
> > +{
> > + size_t len = strlen (arg_str);
> > +
> > + if (len == 0)
> > + {
> > + error_at (loc, "malformed %<target()%> attribute");
> > + return false;
> > + }
> > +
> > + std::unique_ptr<char> buf (new char[len]);
> > + char *str_to_check = buf.get();
> > + strcpy (str_to_check, arg_str);
> > +
> > + char *arg = strchr (str_to_check, '=');
> > +
> > + if (!arg)
> > + {
> > + error_at (
> > + loc,
> > + "attribute %<target(\"%s\")%> does not accept an argument",
> > + str_to_check);
> > + return false;
> > + }
> > +
> > + arg[0] = '\0';
> > + ++arg;
> > + for (const auto &attr : riscv_attributes)
> > + {
> > + /* 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 (strncmp (str_to_check, attr.name, strlen (attr.name)) != 0)
> > + continue;
> > +
> > + return (&attr_parser->*attr.handler) (arg);
> > + }
> > + error_at (loc, "Got unknown attribute %<target(\"%s\")%>", str_to_check);
> > +
> > + return false;
> > +}
> > +
> > +/* 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. */
> > +
> > +static bool
> > +riscv_process_target_attr (tree args, location_t loc, struct gcc_options *opts)
> > +{
> > + if (TREE_CODE (args) == TREE_LIST)
> > + {
> > + do
> > + {
> > + tree head = TREE_VALUE (args);
> > + if (head)
> > + {
> > + if (!riscv_process_target_attr (head, loc, opts))
> > + 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));
> > +
> > + /* No need to emit warning or error on empty string here, generic code already
> > + handle this case. */
> > + if (len == 0)
> > + {
> > + return false;
> > + }
> > +
> > + std::unique_ptr<char> buf (new char[len]);
> > + char *str_to_check = buf.get ();
> > + strcpy (str_to_check, TREE_STRING_POINTER (args));
> > +
> > + /* 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);
> > +
> > + riscv_target_attr_parser attr_parser (loc);
> > + unsigned int num_attrs = 0;
> > + while (token)
> > + {
> > + num_attrs++;
> > + riscv_process_one_target_attr (token, loc, attr_parser);
> > + token = strtok_r (NULL, ";", &str_to_check);
> > + }
> > +
> > + if (num_attrs != num_commas + 1)
> > + {
> > + error_at (loc, "malformed %<target(\"%s\")%> attribute",
> > + TREE_STRING_POINTER (args));
> > + return false;
> > + }
> > +
> > + /* Apply settings from target attribute. */
> > + attr_parser.update_settings (opts);
> > +
> > + return true;
> > +}
> > +
> > +/* Implement TARGET_OPTION_VALID_ATTRIBUTE_P. This is used to
> > + process attribute ((target ("..."))). */
> > +
> > +bool
> > +riscv_option_valid_attribute_p (tree fndecl, tree, tree args, int)
> > +{
> > + struct cl_target_option cur_target;
> > + bool ret;
> > + tree new_target;
> > + location_t loc = DECL_SOURCE_LOCATION (fndecl);
> > +
> > + /* Save the current target options to restore at the end. */
> > + cl_target_option_save (&cur_target, &global_options, &global_options_set);
> > +
> > + ret = riscv_process_target_attr (args, loc, &global_options);
> > +
> > + if (ret)
> > + {
> > + riscv_override_options_internal (&global_options);
> > + new_target
> > + = build_target_option_node (&global_options, &global_options_set);
> > + }
> > + else
> > + new_target = NULL;
> > +
> > + if (fndecl && ret)
> > + {
> > + DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = new_target;
> > + }
> > +
> > + cl_target_option_restore (&global_options, &global_options_set, &cur_target);
> > + return ret;
> > +}
> > diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
> > index f09c4066903..cebd2fc0d25 100644
> > --- a/gcc/config/riscv/riscv.cc
> > +++ b/gcc/config/riscv/riscv.cc
> > @@ -73,10 +73,12 @@ along with GCC; see the file COPYING3. If not see
> > #include "tree-vectorizer.h"
> > #include "gcse.h"
> > #include "tree-dfa.h"
> > +#include "target-globals.h"
> >
> > /* This file should be included last. */
> > #include "target-def.h"
> > #include "riscv-vector-costs.h"
> > +#include "riscv-subset.h"
> >
> > /* True if X is an UNSPEC wrapper around a SYMBOL_REF or LABEL_REF. */
> > #define UNSPEC_ADDRESS_P(X) \
> > @@ -264,17 +266,6 @@ struct riscv_tune_param
> > bool use_divmod_expansion;
> > };
> >
> > -/* Information about one micro-arch we know about. */
> > -struct riscv_tune_info {
> > - /* This micro-arch canonical name. */
> > - const char *name;
> > -
> > - /* Which automaton to use for tuning. */
> > - enum riscv_microarchitecture_type microarchitecture;
> > -
> > - /* Tuning parameters for this micro-arch. */
> > - const struct riscv_tune_param *tune_param;
> > -};
> >
> > /* Global variables for machine-dependent things. */
> >
> > @@ -501,10 +492,23 @@ riscv_min_arithmetic_precision (void)
> > return 32;
> > }
> >
> > -/* Return the riscv_tune_info entry for the given name string. */
> > +template <class T>
> > +static const char *
> > +get_tune_str (const T *opts)
> > +{
> > + const char *tune_string = RISCV_TUNE_STRING_DEFAULT;
> > + if (opts->x_riscv_tune_string)
> > + tune_string = opts->x_riscv_tune_string;
> > + else if (opts->x_riscv_cpu_string)
> > + tune_string = opts->x_riscv_cpu_string;
> > + return tune_string;
> > +}
> > +
> > +/* Return the riscv_tune_info entry for the given name string, return nullptr
> > + if NULL_P is true, otherwise return an placeholder and report error. */
> >
> > -static const struct riscv_tune_info *
> > -riscv_parse_tune (const char *tune_string)
> > +const struct riscv_tune_info *
> > +riscv_parse_tune (const char *tune_string, bool null_p)
> > {
> > const riscv_cpu_info *cpu = riscv_find_cpu (tune_string);
> >
> > @@ -515,6 +519,9 @@ riscv_parse_tune (const char *tune_string)
> > if (strcmp (riscv_tune_info_table[i].name, tune_string) == 0)
> > return riscv_tune_info_table + i;
> >
> > + if (null_p)
> > + return nullptr;
> > +
> > error ("unknown cpu %qs for %<-mtune%>", tune_string);
> > return riscv_tune_info_table;
> > }
> > @@ -7873,6 +7880,33 @@ riscv_declare_function_name (FILE *stream, const char *name, tree fndecl)
> > riscv_asm_output_variant_cc (stream, fndecl, name);
> > ASM_OUTPUT_TYPE_DIRECTIVE (stream, name, "function");
> > ASM_OUTPUT_LABEL (stream, name);
> > + if (DECL_FUNCTION_SPECIFIC_TARGET (fndecl))
> > + {
> > + fprintf (stream, "\t.option push\n");
> > + std::string isa = riscv_current_subset_list ()->to_string (true);
> > + fprintf (stream, "\t.option arch, %s\n", isa.c_str ());
> > +
> > + struct cl_target_option *local_cl_target =
> > + TREE_TARGET_OPTION (DECL_FUNCTION_SPECIFIC_TARGET (fndecl));
> > + struct cl_target_option *global_cl_target =
> > + TREE_TARGET_OPTION (target_option_default_node);
> > + const char *local_tune_str = get_tune_str (local_cl_target);
> > + const char *global_tune_str = get_tune_str (global_cl_target);
> > + if (strcmp (local_tune_str, global_tune_str) != 0)
> > + fprintf (stream, "\t# tune = %s\n", local_tune_str);
> > + }
> > +}
> > +
> > +void
> > +riscv_declare_function_size (FILE *stream, const char *name, tree fndecl)
> > +{
> > + if (!flag_inhibit_size_directive)
> > + ASM_OUTPUT_MEASURED_SIZE (stream, name);
> > +
> > + if (DECL_FUNCTION_SPECIFIC_TARGET (fndecl))
> > + {
> > + fprintf (stream, "\t.option pop\n");
> > + }
> > }
> >
> > /* Implement ASM_OUTPUT_DEF_FROM_DECLS. */
> > @@ -8079,16 +8113,18 @@ riscv_override_options_internal (struct gcc_options *opts)
> > error ("%<-mdiv%> requires %<-march%> to subsume the %<M%> extension");
> >
> > /* Likewise floating-point division and square root. */
> > - if ((TARGET_HARD_FLOAT || TARGET_ZFINX) && (target_flags_explicit & MASK_FDIV) == 0)
> > + if ((TARGET_HARD_FLOAT_OPTS_P (opts) || TARGET_ZFINX_OPTS_P (opts))
> > + && ((target_flags_explicit & MASK_FDIV) == 0))
> > opts->x_target_flags |= MASK_FDIV;
> >
> > /* Handle -mtune, use -mcpu if -mtune is not given, and use default -mtune
> > if both -mtune and -mcpu are not given. */
> > - cpu = riscv_parse_tune (opts->x_riscv_tune_string ? opts->x_riscv_tune_string :
> > - (opts->x_riscv_cpu_string ? opts->x_riscv_cpu_string :
> > - RISCV_TUNE_STRING_DEFAULT));
> > + const char *tune_string = get_tune_str (opts);
> > + cpu = riscv_parse_tune (tune_string, false);
> > riscv_microarchitecture = cpu->microarchitecture;
> > - tune_param = opts->x_optimize_size ? &optimize_size_tune_info : cpu->tune_param;
> > + tune_param = opts->x_optimize_size
> > + ? &optimize_size_tune_info
> > + : cpu->tune_param;
> >
> > /* Use -mtune's setting for slow_unaligned_access, even when optimizing
> > for size. For architectures that trap and emulate unaligned accesses,
> > @@ -8100,7 +8136,7 @@ riscv_override_options_internal (struct gcc_options *opts)
> > /* Make a note if user explicity passed -mstrict-align for later
> > builtin macro generation. Can't use target_flags_explicitly since
> > it is set even for -mno-strict-align. */
> > - riscv_user_wants_strict_align = TARGET_STRICT_ALIGN;
> > + riscv_user_wants_strict_align = TARGET_STRICT_ALIGN_OPTS_P (opts);
> >
> > if ((target_flags_explicit & MASK_STRICT_ALIGN) == 0
> > && cpu->tune_param->slow_unaligned_access)
> > @@ -8258,8 +8294,41 @@ riscv_option_override (void)
> > init_machine_status = &riscv_init_machine_status;
> >
> > riscv_override_options_internal (&global_options);
> > +
> > + /* Save these options as the default ones in case we push and pop them later
> > + while processing functions with potential target attributes. */
> > + target_option_default_node = target_option_current_node
> > + = build_target_option_node (&global_options, &global_options_set);
> > +}
> > +
> > +/* Restore or save the TREE_TARGET_GLOBALS from or to NEW_TREE.
> > + Used by riscv_set_current_function to
> > + make sure optab availability predicates are recomputed when necessary. */
> > +
> > +void
> > +riscv_save_restore_target_globals (tree new_tree)
> > +{
> > + if (TREE_TARGET_GLOBALS (new_tree))
> > + restore_target_globals (TREE_TARGET_GLOBALS (new_tree));
> > + else if (new_tree == target_option_default_node)
> > + restore_target_globals (&default_target_globals);
> > + else
> > + TREE_TARGET_GLOBALS (new_tree) = save_target_globals_default_opts ();
> > }
> >
> > +/* Implements TARGET_OPTION_RESTORE. Restore the backend codegen decisions
> > + using the information saved in PTR. */
> > +
> > +static void
> > +riscv_option_restore (struct gcc_options *opts,
> > + struct gcc_options * /* opts_set */,
> > + struct cl_target_option * /* ptr */)
> > +{
> > + riscv_override_options_internal (opts);
> > +}
> > +
> > +static GTY (()) tree riscv_previous_fndecl;
> > +
> > /* Implement TARGET_CONDITIONAL_REGISTER_USAGE. */
> >
> > static void
> > @@ -8505,7 +8574,12 @@ riscv_get_interrupt_type (tree decl)
> > return MACHINE_MODE;
> > }
> >
> > -/* Implement `TARGET_SET_CURRENT_FUNCTION'. */
> > +/* Implement `TARGET_SET_CURRENT_FUNCTION'. Unpack the codegen decisions
> > + like tuning and ISA features from the DECL_FUNCTION_SPECIFIC_TARGET
> > + of the function, if such exists. This function may be called multiple
> > + times on a single function so use aarch64_previous_fndecl to avoid
> > + setting up identical state. */
> > +
> > /* Sanity cheching for above function attributes. */
> > static void
> > riscv_set_current_function (tree decl)
> > @@ -8513,36 +8587,66 @@ riscv_set_current_function (tree decl)
> > if (decl == NULL_TREE
> > || current_function_decl == NULL_TREE
> > || current_function_decl == error_mark_node
> > - || ! cfun->machine
> > - || cfun->machine->attributes_checked_p)
> > + || ! cfun->machine)
> > return;
> >
> > - cfun->machine->naked_p = riscv_naked_function_p (decl);
> > - cfun->machine->interrupt_handler_p
> > - = riscv_interrupt_type_p (TREE_TYPE (decl));
> > + if (!cfun->machine->attributes_checked_p)
> > + {
> > + cfun->machine->naked_p = riscv_naked_function_p (decl);
> > + cfun->machine->interrupt_handler_p
> > + = riscv_interrupt_type_p (TREE_TYPE (decl));
> >
> > - if (cfun->machine->naked_p && cfun->machine->interrupt_handler_p)
> > - error ("function attributes %qs and %qs are mutually exclusive",
> > - "interrupt", "naked");
> > + if (cfun->machine->naked_p && cfun->machine->interrupt_handler_p)
> > + error ("function attributes %qs and %qs are mutually exclusive",
> > + "interrupt", "naked");
> >
> > - if (cfun->machine->interrupt_handler_p)
> > - {
> > - tree ret = TREE_TYPE (TREE_TYPE (decl));
> > - tree args = TYPE_ARG_TYPES (TREE_TYPE (decl));
> > + if (cfun->machine->interrupt_handler_p)
> > + {
> > + tree ret = TREE_TYPE (TREE_TYPE (decl));
> > + tree args = TYPE_ARG_TYPES (TREE_TYPE (decl));
> > +
> > + if (TREE_CODE (ret) != VOID_TYPE)
> > + error ("%qs function cannot return a value", "interrupt");
> >
> > - if (TREE_CODE (ret) != VOID_TYPE)
> > - error ("%qs function cannot return a value", "interrupt");
> > + if (args && TREE_CODE (TREE_VALUE (args)) != VOID_TYPE)
> > + error ("%qs function cannot have arguments", "interrupt");
> >
> > - if (args && TREE_CODE (TREE_VALUE (args)) != VOID_TYPE)
> > - error ("%qs function cannot have arguments", "interrupt");
> > + cfun->machine->interrupt_mode = riscv_get_interrupt_type (decl);
> >
> > - cfun->machine->interrupt_mode = riscv_get_interrupt_type (decl);
> > + gcc_assert (cfun->machine->interrupt_mode != UNKNOWN_MODE);
> > + }
> >
> > - gcc_assert (cfun->machine->interrupt_mode != UNKNOWN_MODE);
> > + /* Don't print the above diagnostics more than once. */
> > + cfun->machine->attributes_checked_p = 1;
> > }
> >
> > - /* Don't print the above diagnostics more than once. */
> > - cfun->machine->attributes_checked_p = 1;
> > + if (!decl || decl == riscv_previous_fndecl)
> > + return;
> > +
> > + tree old_tree = (riscv_previous_fndecl
> > + ? DECL_FUNCTION_SPECIFIC_TARGET (riscv_previous_fndecl)
> > + : NULL_TREE);
> > +
> > + tree new_tree = DECL_FUNCTION_SPECIFIC_TARGET (decl);
> > +
> > + /* If current function has no attributes but the previous one did,
> > + use the default node. */
> > + if (!new_tree && old_tree)
> > + new_tree = target_option_default_node;
> > +
> > + /* If nothing to do, return. #pragma GCC reset or #pragma GCC pop to
> > + the default have been handled by aarch64_save_restore_target_globals from
> > + aarch64_pragma_target_parse. */
> > + if (old_tree == new_tree)
> > + return;
> > +
> > + riscv_previous_fndecl = decl;
> > +
> > + /* First set the target options. */
> > + cl_target_option_restore (&global_options, &global_options_set,
> > + TREE_TARGET_OPTION (new_tree));
> > +
> > + riscv_save_restore_target_globals (new_tree);
> > }
> >
> > /* Implement TARGET_MERGE_DECL_ATTRIBUTES. */
> > @@ -9664,6 +9768,12 @@ riscv_preferred_else_value (unsigned ifn, tree vectype, unsigned int nops,
> > #undef TARGET_OPTION_OVERRIDE
> > #define TARGET_OPTION_OVERRIDE riscv_option_override
> >
> > +#undef TARGET_OPTION_RESTORE
> > +#define TARGET_OPTION_RESTORE riscv_option_restore
> > +
> > +#undef TARGET_OPTION_VALID_ATTRIBUTE_P
> > +#define TARGET_OPTION_VALID_ATTRIBUTE_P riscv_option_valid_attribute_p
> > +
> > #undef TARGET_LEGITIMIZE_ADDRESS
> > #define TARGET_LEGITIMIZE_ADDRESS riscv_legitimize_address
> >
> > diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
> > index 1e9813b4f39..6205d7533f4 100644
> > --- a/gcc/config/riscv/riscv.h
> > +++ b/gcc/config/riscv/riscv.h
> > @@ -25,6 +25,8 @@ along with GCC; see the file COPYING3. If not see
> > #include <stdbool.h>
> > #include "config/riscv/riscv-opts.h"
> >
> > +#define SWITCHABLE_TARGET 1
> > +
> > /* Target CPU builtins. */
> > #define TARGET_CPU_CPP_BUILTINS() riscv_cpu_cpp_builtins (pfile)
> >
> > @@ -1056,6 +1058,10 @@ while (0)
> > #define ASM_DECLARE_FUNCTION_NAME(STR, NAME, DECL) \
> > riscv_declare_function_name (STR, NAME, DECL)
> >
> > +#undef ASM_DECLARE_FUNCTION_SIZE
> > +#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \
> > + riscv_declare_function_size (FILE, FNAME, DECL)
> > +
> > /* Add output .variant_cc directive for specific alias definition. */
> > #undef ASM_OUTPUT_DEF_FROM_DECLS
> > #define ASM_OUTPUT_DEF_FROM_DECLS(STR, DECL, TARGET) \
> > diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
> > index 70d78151cee..1bd661a3fe4 100644
> > --- a/gcc/config/riscv/riscv.opt
> > +++ b/gcc/config/riscv/riscv.opt
> > @@ -84,11 +84,11 @@ Target RejectNegative Joined Negative(march=)
> > lower-case.
> >
> > mtune=
> > -Target RejectNegative Joined Var(riscv_tune_string)
> > +Target RejectNegative Joined Var(riscv_tune_string) Save
> > -mtune=PROCESSOR Optimize the output for PROCESSOR.
> >
> > mcpu=
> > -Target RejectNegative Joined Var(riscv_cpu_string)
> > +Target RejectNegative Joined Var(riscv_cpu_string) Save
> > -mcpu=PROCESSOR Use architecture of and optimize the output for PROCESSOR.
> >
> > msmall-data-limit=
> > @@ -106,7 +106,7 @@ memory accesses to be generated as compressed instructions. Currently targets
> > 32-bit integer load/stores.
> >
> > mcmodel=
> > -Target RejectNegative Joined Enum(code_model) Var(riscv_cmodel) Init(TARGET_DEFAULT_CMODEL)
> > +Target RejectNegative Joined Enum(code_model) Var(riscv_cmodel) Init(TARGET_DEFAULT_CMODEL) Save
> > Specify the code model.
> >
> > mstrict-align
> > diff --git a/gcc/config/riscv/t-riscv b/gcc/config/riscv/t-riscv
> > index 95becfc819b..3b9686daa58 100644
> > --- a/gcc/config/riscv/t-riscv
> > +++ b/gcc/config/riscv/t-riscv
> > @@ -115,6 +115,11 @@ riscv-v.o: $(srcdir)/config/riscv/riscv-v.cc \
> > $(COMPILE) $<
> > $(POSTCOMPILE)
> >
> > +riscv-target-attr.o: $(srcdir)/config/riscv/riscv-target-attr.cc $(CONFIG_H) \
> > + $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(DIAGNOSTIC_CORE_H)
> > + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
> > + $(srcdir)/config/riscv/riscv-target-attr.cc
> > +
> > thead.o: $(srcdir)/config/riscv/thead.cc \
> > $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TARGET_H) backend.h $(RTL_H) \
> > memmodel.h $(EMIT_RTL_H) poly-int.h output.h
> > diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> > index 7cdfdf8c83b..856dd93d16a 100644
> > --- a/gcc/doc/extend.texi
> > +++ b/gcc/doc/extend.texi
> > @@ -6295,8 +6295,66 @@ void f (void) __attribute__ ((interrupt ("user")));
> > Permissible values for this parameter are @code{user}, @code{supervisor},
> > and @code{machine}. If there is no parameter, then it defaults to
> > @code{machine}.
> > +
> > +@end table
> > +
> > +The following target-specific function attributes are available for the
> > +RISC-V target. For the most part, these options mirror the behavior of
> > +similar command-line options (@pxref{RISC-V Options}), but on a
> > +per-function basis.
> > +
> > +@table @code
> > +@cindex @code{arch=} function attribute, RISC-V
> > +@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, in addtion, it also support
> > +extension enablement list, a list of extension name and prefixed with @code{+},
> > +like @code{arch=+zba} means enable @code{zba} extension.
> > +Multiple extension can be enabled by separating them with a comma. For example:
> > +@code{arch=+zba,+zbb}.
> > +
> > +@cindex @code{tune=} function attribute, RISC-V
> > +@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{cpu=} function attribute, RISC-V
> > +@item cpu=
> > +Specifies the core for which to tune the performance of this function and also
> > +whose architectural features to use. The behavior and valid arguments are the
> > +same as for the @option{-mcpu=} command-line option.
> > +
> > @end table
> >
> > +The above target attributes can be specified as follows:
> > +
> > +@smallexample
> > +__attribute__((target("@var{attr-string}")))
> > +int
> > +f (int a)
> > +@{
> > + return a + 5;
> > +@}
> > +@end smallexample
> > +
> > +where @code{@var{attr-string}} is one of the attribute strings specified above.
> > +
> > +Multiple target function attributes can be specified by separating them with
> > +a semicolon. For example:
> > +@smallexample
> > +__attribute__((target("arch=+zba,+zbb;tune=rocket")))
> > +int
> > +foo (int a)
> > +@{
> > + return a + 5;
> > +@}
> > +@end smallexample
> > +
> > +is valid and compiles function @code{foo} with @code{zba}
> > +and @code{zbb} extensions and tunes it for @code{rocket}.
> > +
> > @node RL78 Function Attributes
> > @subsection RL78 Function Attributes
> >
> > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-01.c b/gcc/testsuite/gcc.target/riscv/target-attr-01.c
> > new file mode 100644
> > index 00000000000..b3f3d65d543
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-01.c
> > @@ -0,0 +1,31 @@
> > +/* { dg-do compile } */
> > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> > +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> > +/* { dg-final { check-function-bodies "**" "" } } */
> > +
> > +
> > +/*
> > +** foo:
> > +** ...
> > +** sh1add\s*a0,a1,a0
> > +** ...
> > +*/
> > +
> > +
> > +long foo() __attribute__((target("arch=rv64gc_zba")));
> > +long foo(long a, long b){
> > + return a + (b * 2);
> > +}
> > +
> > +/*
> > +** bar:
> > +** ...
> > +** slli\s*a1,a1,1
> > +** add\s*a0,a1,a0
> > +** ...
> > +*/
> > +
> > +
> > +long bar(long a, long b){
> > + return a + (b * 2);
> > +}
> > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-02.c b/gcc/testsuite/gcc.target/riscv/target-attr-02.c
> > new file mode 100644
> > index 00000000000..c010089a823
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-02.c
> > @@ -0,0 +1,31 @@
> > +/* { dg-do compile } */
> > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> > +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> > +/* { dg-final { check-function-bodies "**" "" } } */
> > +
> > +
> > +/*
> > +** foo:
> > +** ...
> > +** sh1add\s*a0,a1,a0
> > +** ...
> > +*/
> > +
> > +
> > +long foo() __attribute__((target("arch=+zba")));
> > +long foo(long a, long b){
> > + return a + (b * 2);
> > +}
> > +
> > +/*
> > +** bar:
> > +** ...
> > +** slli\s*a1,a1,1
> > +** add\s*a0,a1,a0
> > +** ...
> > +*/
> > +
> > +
> > +long bar(long a, long b){
> > + return a + (b * 2);
> > +}
> > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-03.c b/gcc/testsuite/gcc.target/riscv/target-attr-03.c
> > new file mode 100644
> > index 00000000000..b4896cb2e27
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-03.c
> > @@ -0,0 +1,26 @@
> > +/* { dg-do compile } */
> > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> > +/* { dg-options "-march=rv64gc_zba -O2 -mabi=lp64" } */
> > +/* { dg-final { check-function-bodies "**" "" } } */
> > +
> > +/*
> > +** foo:
> > +** ...
> > +** slli\s*a1,a1,1
> > +** add\s*a0,a1,a0
> > +** ...
> > +*/
> > +long foo() __attribute__((target("arch=rv64gc")));
> > +long foo(long a, long b){
> > + return a + (b * 2);
> > +}
> > +
> > +/*
> > +** bar:
> > +** ...
> > +** sh1add\s*a0,a1,a0
> > +** ...
> > +*/
> > +long bar(long a, long b){
> > + return a + (b * 2);
> > +}
> > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-04.c b/gcc/testsuite/gcc.target/riscv/target-attr-04.c
> > new file mode 100644
> > index 00000000000..369d6514e5a
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-04.c
> > @@ -0,0 +1,28 @@
> > +/* { dg-do compile } */
> > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> > +/* { dg-options "-march=rv64gc_zba -O2 -mabi=lp64 -mtune=rocket" } */
> > +/* { dg-final { check-function-bodies "**" "" } } */
> > +
> > +/*
> > +** foo:
> > +** ...
> > +** # tune = sifive-7-series
> > +** ...
> > +** slli\s*a1,a1,1
> > +** add\s*a0,a1,a0
> > +** ...
> > +*/
> > +long foo() __attribute__((target("cpu=sifive-u74")));
> > +long foo(long a, long b){
> > + return a + (b * 2);
> > +}
> > +
> > +/*
> > +** bar:
> > +** ...
> > +** sh1add\s*a0,a1,a0
> > +** ...
> > +*/
> > +long bar(long a, long b){
> > + return a + (b * 2);
> > +}
> > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-05.c b/gcc/testsuite/gcc.target/riscv/target-attr-05.c
> > new file mode 100644
> > index 00000000000..c75368dcebf
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-05.c
> > @@ -0,0 +1,27 @@
> > +/* { dg-do compile } */
> > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> > +/* { dg-options "-march=rv64gc_zba -O2 -mabi=lp64 -mtune=rocket" } */
> > +/* { dg-final { check-function-bodies "**" "" } } */
> > +
> > +/*
> > +** foo:
> > +** ...
> > +** # tune = sifive-7-series
> > +** ...
> > +** sh1add\s*a0,a1,a0
> > +** ...
> > +*/
> > +long foo() __attribute__((target("cpu=sifive-u74;arch=rv64gc_zba")));
> > +long foo(long a, long b){
> > + return a + (b * 2);
> > +}
> > +
> > +/*
> > +** bar:
> > +** ...
> > +** sh1add\s*a0,a1,a0
> > +** ...
> > +*/
> > +long bar(long a, long b){
> > + return a + (b * 2);
> > +}
> > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-06.c b/gcc/testsuite/gcc.target/riscv/target-attr-06.c
> > new file mode 100644
> > index 00000000000..369c95eeb54
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-06.c
> > @@ -0,0 +1,27 @@
> > +/* { dg-do compile } */
> > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> > +/* { dg-options "-march=rv64gc_zba -O2 -mabi=lp64 -mtune=rocket" } */
> > +/* { dg-final { check-function-bodies "**" "" } } */
> > +
> > +/*
> > +** foo:
> > +** ...
> > +** # tune = sifive-5-series
> > +** ...
> > +** sh1add\s*a0,a1,a0
> > +** ...
> > +*/
> > +long foo() __attribute__((target("cpu=sifive-u74;tune=sifive-5-series;arch=rv64gc_zba")));
> > +long foo(long a, long b){
> > + return a + (b * 2);
> > +}
> > +
> > +/*
> > +** bar:
> > +** ...
> > +** sh1add\s*a0,a1,a0
> > +** ...
> > +*/
> > +long bar(long a, long b){
> > + return a + (b * 2);
> > +}
> > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-07.c b/gcc/testsuite/gcc.target/riscv/target-attr-07.c
> > new file mode 100644
> > index 00000000000..4ff81166a62
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-07.c
> > @@ -0,0 +1,25 @@
> > +/* { dg-do compile } */
> > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> > +/* { dg-options "-march=rv64gc_zba -O2 -mabi=lp64 -mtune=rocket" } */
> > +/* { dg-final { check-function-bodies "**" "" } } */
> > +
> > +/*
> > +** foo:
> > +** ...
> > +** # tune = sifive-5-series
> > +** ...
> > +*/
> > +long foo() __attribute__((target("tune=sifive-5-series")));
> > +long foo(long a, long b){
> > + return a + (b * 2);
> > +}
> > +
> > +/*
> > +** bar:
> > +** ...
> > +** sh1add\s*a0,a1,a0
> > +** ...
> > +*/
> > +long bar(long a, long b){
> > + return a + (b * 2);
> > +}
> > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-01.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-01.c
> > new file mode 100644
> > index 00000000000..91cbcaac21d
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-01.c
> > @@ -0,0 +1,13 @@
> > +/* { dg-do compile } */
> > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> > +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> > +
> > +
> > +long foo() __attribute__((target("arch=rv64gc_zba;;"))); /* { dg-error "malformed" } */
> > +long foo(long a, long b){
> > + return a + (b * 2);
> > +}
> > +
> > +long bar(long a, long b){
> > + return a + (b * 2);
> > +}
> > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-02.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-02.c
> > new file mode 100644
> > index 00000000000..0c838bb3ca7
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-02.c
> > @@ -0,0 +1,13 @@
> > +/* { dg-do compile } */
> > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> > +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> > +
> > +
> > +long foo() __attribute__((target("cpu=xyz-cpu"))); /* { dg-error "unknown CPU" } */
> > +long foo(long a, long b){
> > + return a + (b * 2);
> > +}
> > +
> > +long bar(long a, long b){
> > + return a + (b * 2);
> > +}
> > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-03.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-03.c
> > new file mode 100644
> > index 00000000000..09702d1690a
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-03.c
> > @@ -0,0 +1,13 @@
> > +/* { dg-do compile } */
> > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> > +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> > +
> > +
> > +long foo() __attribute__((target("tune=xyz-cpu"))); /* { dg-error "unknown TUNE" } */
> > +long foo(long a, long b){
> > + return a + (b * 2);
> > +}
> > +
> > +long bar(long a, long b){
> > + return a + (b * 2);
> > +}
> > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-04.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-04.c
> > new file mode 100644
> > index 00000000000..1d9a0ffdd88
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-04.c
> > @@ -0,0 +1,13 @@
> > +/* { dg-do compile } */
> > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> > +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> > +
> > +
> > +long foo() __attribute__((target(123))); /* { dg-error "argument not a string" } */
> > +long foo(long a, long b){
> > + return a + (b * 2);
> > +}
> > +
> > +long bar(long a, long b){
> > + return a + (b * 2);
> > +}
> > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-05.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-05.c
> > new file mode 100644
> > index 00000000000..24a81c5279b
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-05.c
> > @@ -0,0 +1,13 @@
> > +/* { dg-do compile } */
> > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> > +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> > +
> > +
> > +long foo() __attribute__((target(""))); /* { dg-warning "empty string in attribute .target." } */
> > +long foo(long a, long b){
> > + return a + (b * 2);
> > +}
> > +
> > +long bar(long a, long b){
> > + return a + (b * 2);
> > +}
> > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-06.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-06.c
> > new file mode 100644
> > index 00000000000..a0d65859d40
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-06.c
> > @@ -0,0 +1,13 @@
> > +/* { dg-do compile } */
> > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> > +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> > +
> > +
> > +long foo() __attribute__((target("arch=*x"))); /* { dg-error "must start with \\+ or rv" } */
> > +long foo(long a, long b){
> > + return a + (b * 2);
> > +}
> > +
> > +long bar(long a, long b){
> > + return a + (b * 2);
> > +}
> > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-07.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-07.c
> > new file mode 100644
> > index 00000000000..8aa82504dc1
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-07.c
> > @@ -0,0 +1,13 @@
> > +/* { dg-do compile } */
> > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> > +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> > +
> > +
> > +long foo() __attribute__((target("arch=+zbb_zba"))); /* { dg-error "extension 'zbb_zba' starts with 'z' but is unsupported standard extension" } */
> > +long foo(long a, long b){
> > + return a + (b * 2);
> > +}
> > +
> > +long bar(long a, long b){
> > + return a + (b * 2);
> > +}
> > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-08.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-08.c
> > new file mode 100644
> > index 00000000000..68d211de887
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-08.c
> > @@ -0,0 +1,8 @@
> > +/* { dg-do compile } */
> > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> > +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> > +
> > +long foo() __attribute__((target("arch=rv64gc_zba;arch=rv64gc_zba"))); /* { dg-error "arch appears more than once" } */
> > +long foo(long a, long b){
> > + return a + (b * 2);
> > +}
> > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-09.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-09.c
> > new file mode 100644
> > index 00000000000..2b6e4982894
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-09.c
> > @@ -0,0 +1,8 @@
> > +/* { dg-do compile } */
> > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> > +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> > +
> > +long foo() __attribute__((target("cpu=sifive-u74;cpu=sifive-u74"))); /* { dg-error "cpu appears more than once" } */
> > +long foo(long a, long b){
> > + return a + (b * 2);
> > +}
> > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-bad-10.c b/gcc/testsuite/gcc.target/riscv/target-attr-bad-10.c
> > new file mode 100644
> > index 00000000000..00cefa03e41
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-bad-10.c
> > @@ -0,0 +1,8 @@
> > +/* { dg-do compile } */
> > +/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> > +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> > +
> > +long foo() __attribute__((target("tune=sifive-u74;tune=sifive-u74"))); /* { dg-error "tune appears more than once" } */
> > +long foo(long a, long b){
> > + return a + (b * 2);
> > +}
> > --
> > 2.40.1
> >
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2] RISC-V: Implement target attribute
2023-11-14 14:15 [PATCH v2] RISC-V: Implement target attribute Kito Cheng
2023-11-14 14:17 ` Kito Cheng
2023-11-15 23:58 ` Christoph Müllner
@ 2023-11-17 15:41 ` Andreas Schwab
2023-11-18 10:44 ` Kito Cheng
2 siblings, 1 reply; 6+ messages in thread
From: Andreas Schwab @ 2023-11-17 15:41 UTC (permalink / raw)
To: Kito Cheng; +Cc: gcc-patches, kito.cheng, palmer, jeffreyalaw
In file included from /daten/riscv64/gcc/gcc-20231117/Build/prev-riscv64-suse-linux/libstdc++-v3/include/memory:78,
from ../../gcc/system.h:769,
from ../../gcc/config/riscv/riscv-target-attr.cc:25:
In member function 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = char]',
inlined from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = char; _Dp = std::default_delete<char>]' at /daten/riscv64/gcc/gcc-20231117/Build/prev-riscv64-suse-linux/libstdc++-v3/include/bits/unique_ptr.h:398:17,
inlined from 'bool riscv_process_one_target_attr(char*, location_t, {anonymous}::riscv_target_attr_parser&)' at ../../gcc/config/riscv/riscv-target-attr.cc:274:1,
inlined from 'bool riscv_process_target_attr(tree, location_t, gcc_options*)' at ../../gcc/config/riscv/riscv-target-attr.cc:346:37:
/daten/riscv64/gcc/gcc-20231117/Build/prev-riscv64-suse-linux/libstdc++-v3/include/bits/unique_ptr.h:93:9: error: 'void operator delete(void*, std::size_t)' called on pointer returned from a mismatched allocation function [-Werror=mismatched-new-delete]
93 | delete __ptr;
| ^~~~~~~~~~~~
In function 'bool riscv_process_one_target_attr(char*, location_t, {anonymous}::riscv_target_attr_parser&)',
inlined from 'bool riscv_process_target_attr(tree, location_t, gcc_options*)' at ../../gcc/config/riscv/riscv-target-attr.cc:346:37:
../../gcc/config/riscv/riscv-target-attr.cc:244:42: note: returned from 'void* operator new [](std::size_t)'
244 | std::unique_ptr<char> buf (new char[len]);
| ^
In member function 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = char]',
inlined from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = char; _Dp = std::default_delete<char>]' at /daten/riscv64/gcc/gcc-20231117/Build/prev-riscv64-suse-linux/libstdc++-v3/include/bits/unique_ptr.h:398:17,
inlined from 'bool riscv_process_target_attr(tree, location_t, gcc_options*)' at ../../gcc/config/riscv/riscv-target-attr.cc:361:1:
/daten/riscv64/gcc/gcc-20231117/Build/prev-riscv64-suse-linux/libstdc++-v3/include/bits/unique_ptr.h:93:9: error: 'void operator delete(void*, std::size_t)' called on pointer returned from a mismatched allocation function [-Werror=mismatched-new-delete]
93 | delete __ptr;
| ^~~~~~~~~~~~
../../gcc/config/riscv/riscv-target-attr.cc: In function 'bool riscv_process_target_attr(tree, location_t, gcc_options*)':
../../gcc/config/riscv/riscv-target-attr.cc:330:42: note: returned from 'void* operator new [](std::size_t)'
330 | std::unique_ptr<char> buf (new char[len]);
| ^
In member function 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = char]',
inlined from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = char; _Dp = std::default_delete<char>]' at /daten/riscv64/gcc/gcc-20231117/Build/prev-riscv64-suse-linux/libstdc++-v3/include/bits/unique_ptr.h:398:17,
inlined from 'bool {anonymous}::riscv_target_attr_parser::parse_arch(const char*)' at ../../gcc/config/riscv/riscv-target-attr.cc:140:5,
inlined from 'bool {anonymous}::riscv_target_attr_parser::handle_arch(const char*)' at ../../gcc/config/riscv/riscv-target-attr.cc:158:21:
/daten/riscv64/gcc/gcc-20231117/Build/prev-riscv64-suse-linux/libstdc++-v3/include/bits/unique_ptr.h:93:9: error: 'void operator delete(void*, std::size_t)' called on pointer returned from a mismatched allocation function [-Werror=mismatched-new-delete]
93 | delete __ptr;
| ^~~~~~~~~~~~
In member function 'bool {anonymous}::riscv_target_attr_parser::parse_arch(const char*)',
inlined from 'bool {anonymous}::riscv_target_attr_parser::handle_arch(const char*)' at ../../gcc/config/riscv/riscv-target-attr.cc:158:21:
../../gcc/config/riscv/riscv-target-attr.cc:108:46: note: returned from 'void* operator new [](std::size_t)'
108 | std::unique_ptr<char> buf (new char[len]);
| ^
In member function 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = char]',
inlined from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = char; _Dp = std::default_delete<char>]' at /daten/riscv64/gcc/gcc-20231117/Build/prev-riscv64-suse-linux/libstdc++-v3/include/bits/unique_ptr.h:398:17,
inlined from 'bool {anonymous}::riscv_target_attr_parser::parse_arch(const char*)' at ../../gcc/config/riscv/riscv-target-attr.cc:140:5,
inlined from 'bool {anonymous}::riscv_target_attr_parser::handle_arch(const char*)' at ../../gcc/config/riscv/riscv-target-attr.cc:158:21:
/daten/riscv64/gcc/gcc-20231117/Build/prev-riscv64-suse-linux/libstdc++-v3/include/bits/unique_ptr.h:93:9: error: 'void operator delete(void*, std::size_t)' called on pointer returned from a mismatched allocation function [-Werror=mismatched-new-delete]
93 | delete __ptr;
| ^~~~~~~~~~~~
In member function 'bool {anonymous}::riscv_target_attr_parser::parse_arch(const char*)',
inlined from 'bool {anonymous}::riscv_target_attr_parser::handle_arch(const char*)' at ../../gcc/config/riscv/riscv-target-attr.cc:158:21:
../../gcc/config/riscv/riscv-target-attr.cc:108:46: note: returned from 'void* operator new [](std::size_t)'
108 | std::unique_ptr<char> buf (new char[len]);
| ^
cc1plus: all warnings being treated as errors
make[3]: *** [../../gcc/config/riscv/t-riscv:120: riscv-target-attr.o] Error 1
--
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510 2552 DF73 E780 A9DA AEC1
"And now for something completely different."
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2] RISC-V: Implement target attribute
2023-11-17 15:41 ` Andreas Schwab
@ 2023-11-18 10:44 ` Kito Cheng
0 siblings, 0 replies; 6+ messages in thread
From: Kito Cheng @ 2023-11-18 10:44 UTC (permalink / raw)
To: Andreas Schwab; +Cc: gcc-patches, kito.cheng, palmer, jeffreyalaw
Fixed on upstream, thanks for reporting, I guess my host GCC is just
too old. It doesn't even not report that bug with -Wall -Wextra..
On Fri, Nov 17, 2023 at 11:41 PM Andreas Schwab <schwab@linux-m68k.org> wrote:
>
> In file included from /daten/riscv64/gcc/gcc-20231117/Build/prev-riscv64-suse-linux/libstdc++-v3/include/memory:78,
> from ../../gcc/system.h:769,
> from ../../gcc/config/riscv/riscv-target-attr.cc:25:
> In member function 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = char]',
> inlined from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = char; _Dp = std::default_delete<char>]' at /daten/riscv64/gcc/gcc-20231117/Build/prev-riscv64-suse-linux/libstdc++-v3/include/bits/unique_ptr.h:398:17,
> inlined from 'bool riscv_process_one_target_attr(char*, location_t, {anonymous}::riscv_target_attr_parser&)' at ../../gcc/config/riscv/riscv-target-attr.cc:274:1,
> inlined from 'bool riscv_process_target_attr(tree, location_t, gcc_options*)' at ../../gcc/config/riscv/riscv-target-attr.cc:346:37:
> /daten/riscv64/gcc/gcc-20231117/Build/prev-riscv64-suse-linux/libstdc++-v3/include/bits/unique_ptr.h:93:9: error: 'void operator delete(void*, std::size_t)' called on pointer returned from a mismatched allocation function [-Werror=mismatched-new-delete]
> 93 | delete __ptr;
> | ^~~~~~~~~~~~
> In function 'bool riscv_process_one_target_attr(char*, location_t, {anonymous}::riscv_target_attr_parser&)',
> inlined from 'bool riscv_process_target_attr(tree, location_t, gcc_options*)' at ../../gcc/config/riscv/riscv-target-attr.cc:346:37:
> ../../gcc/config/riscv/riscv-target-attr.cc:244:42: note: returned from 'void* operator new [](std::size_t)'
> 244 | std::unique_ptr<char> buf (new char[len]);
> | ^
> In member function 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = char]',
> inlined from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = char; _Dp = std::default_delete<char>]' at /daten/riscv64/gcc/gcc-20231117/Build/prev-riscv64-suse-linux/libstdc++-v3/include/bits/unique_ptr.h:398:17,
> inlined from 'bool riscv_process_target_attr(tree, location_t, gcc_options*)' at ../../gcc/config/riscv/riscv-target-attr.cc:361:1:
> /daten/riscv64/gcc/gcc-20231117/Build/prev-riscv64-suse-linux/libstdc++-v3/include/bits/unique_ptr.h:93:9: error: 'void operator delete(void*, std::size_t)' called on pointer returned from a mismatched allocation function [-Werror=mismatched-new-delete]
> 93 | delete __ptr;
> | ^~~~~~~~~~~~
> ../../gcc/config/riscv/riscv-target-attr.cc: In function 'bool riscv_process_target_attr(tree, location_t, gcc_options*)':
> ../../gcc/config/riscv/riscv-target-attr.cc:330:42: note: returned from 'void* operator new [](std::size_t)'
> 330 | std::unique_ptr<char> buf (new char[len]);
> | ^
> In member function 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = char]',
> inlined from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = char; _Dp = std::default_delete<char>]' at /daten/riscv64/gcc/gcc-20231117/Build/prev-riscv64-suse-linux/libstdc++-v3/include/bits/unique_ptr.h:398:17,
> inlined from 'bool {anonymous}::riscv_target_attr_parser::parse_arch(const char*)' at ../../gcc/config/riscv/riscv-target-attr.cc:140:5,
> inlined from 'bool {anonymous}::riscv_target_attr_parser::handle_arch(const char*)' at ../../gcc/config/riscv/riscv-target-attr.cc:158:21:
> /daten/riscv64/gcc/gcc-20231117/Build/prev-riscv64-suse-linux/libstdc++-v3/include/bits/unique_ptr.h:93:9: error: 'void operator delete(void*, std::size_t)' called on pointer returned from a mismatched allocation function [-Werror=mismatched-new-delete]
> 93 | delete __ptr;
> | ^~~~~~~~~~~~
> In member function 'bool {anonymous}::riscv_target_attr_parser::parse_arch(const char*)',
> inlined from 'bool {anonymous}::riscv_target_attr_parser::handle_arch(const char*)' at ../../gcc/config/riscv/riscv-target-attr.cc:158:21:
> ../../gcc/config/riscv/riscv-target-attr.cc:108:46: note: returned from 'void* operator new [](std::size_t)'
> 108 | std::unique_ptr<char> buf (new char[len]);
> | ^
> In member function 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = char]',
> inlined from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = char; _Dp = std::default_delete<char>]' at /daten/riscv64/gcc/gcc-20231117/Build/prev-riscv64-suse-linux/libstdc++-v3/include/bits/unique_ptr.h:398:17,
> inlined from 'bool {anonymous}::riscv_target_attr_parser::parse_arch(const char*)' at ../../gcc/config/riscv/riscv-target-attr.cc:140:5,
> inlined from 'bool {anonymous}::riscv_target_attr_parser::handle_arch(const char*)' at ../../gcc/config/riscv/riscv-target-attr.cc:158:21:
> /daten/riscv64/gcc/gcc-20231117/Build/prev-riscv64-suse-linux/libstdc++-v3/include/bits/unique_ptr.h:93:9: error: 'void operator delete(void*, std::size_t)' called on pointer returned from a mismatched allocation function [-Werror=mismatched-new-delete]
> 93 | delete __ptr;
> | ^~~~~~~~~~~~
> In member function 'bool {anonymous}::riscv_target_attr_parser::parse_arch(const char*)',
> inlined from 'bool {anonymous}::riscv_target_attr_parser::handle_arch(const char*)' at ../../gcc/config/riscv/riscv-target-attr.cc:158:21:
> ../../gcc/config/riscv/riscv-target-attr.cc:108:46: note: returned from 'void* operator new [](std::size_t)'
> 108 | std::unique_ptr<char> buf (new char[len]);
> | ^
> cc1plus: all warnings being treated as errors
> make[3]: *** [../../gcc/config/riscv/t-riscv:120: riscv-target-attr.o] Error 1
>
> --
> Andreas Schwab, schwab@linux-m68k.org
> GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510 2552 DF73 E780 A9DA AEC1
> "And now for something completely different."
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2023-11-18 10:44 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-11-14 14:15 [PATCH v2] RISC-V: Implement target attribute Kito Cheng
2023-11-14 14:17 ` Kito Cheng
2023-11-15 23:58 ` Christoph Müllner
2023-11-16 11:40 ` Kito Cheng
2023-11-17 15:41 ` Andreas Schwab
2023-11-18 10:44 ` Kito Cheng
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).