Committed with changelog update :P Thanks for the review.
On Thu, Nov 16, 2023 at 7:59 AM Christoph Müllner <christoph.muell...@vrull.eu> wrote: > > On Tue, Nov 14, 2023 at 3:15 PM Kito Cheng <kito.ch...@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.muell...@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 > >