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> ``` [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-opts.h (TARGET_MIN_VLEN_OPTS): New. * 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-warning-01.c: Ditto. * gcc.target/riscv/target-attr-warning-02.c: Ditto. * gcc.target/riscv/target-attr-warning-03.c: Ditto. --- gcc/config.gcc | 2 +- gcc/config/riscv/riscv-opts.h | 6 + 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-warning-01.c | 8 + .../gcc.target/riscv/target-attr-warning-02.c | 8 + .../gcc.target/riscv/target-attr-warning-03.c | 8 + 26 files changed, 956 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-warning-01.c create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-warning-02.c create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-warning-03.c diff --git a/gcc/config.gcc b/gcc/config.gcc index cc37a9c768d..4c3d5cb2c8a 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -545,7 +545,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" 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-opts.h b/gcc/config/riscv/riscv-opts.h index e7c6b75c5ea..31ee42dea6b 100644 --- a/gcc/config/riscv/riscv-opts.h +++ b/gcc/config/riscv/riscv-opts.h @@ -112,6 +112,12 @@ enum riscv_entity ? 0 \ : 32 << (__builtin_popcount (riscv_zvl_flags) - 1)) +/* Same as TARGET_MIN_VLEN, but take an OPTS as gcc_options. */ +#define TARGET_MIN_VLEN_OPTS(opts) \ + ((opts->x_riscv_zvl_flags == 0) \ + ? 0 \ + : 32 << (__builtin_popcount (opts->x_riscv_zvl_flags) - 1)) + /* We only enable VLS modes for VLA vectorization since fixed length VLMAX mode is the highest priority choice and should not conflict with VLS modes. */ #define TARGET_VECTOR_VLS \ diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index 43426a5326b..eb23eb1e78f 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -103,6 +103,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 @@ -579,5 +580,25 @@ th_mempair_output_move (rtx[4], bool, machine_mode, RTX_CODE); 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..33cff2c222f --- /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_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); + char *str_to_check = (char *) alloca (len + 1); + 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) + warning_at (m_loc, 0, + "%<target()%> attribute: arch appears more than once, the " + "settings of the last one will be used"); + 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) + warning_at (m_loc, 0, + "%<target()%> attribute: cpu appears more than once, the " + "settings of the last one will be used"); + + 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) + warning_at (m_loc, 0, + "%<target()%> attribute: tune appears more than once, the " + "settings of the last one will be used"); + 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; + } + + char *str_to_check = (char *) alloca (len + 1); + 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)); + char *str_to_check = (char *) alloca (len + 1); + strcpy (str_to_check, 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; + + /* 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 c7d0d300345..61c601f78b5 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) \ @@ -261,17 +263,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. */ @@ -498,10 +489,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); @@ -512,6 +516,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; } @@ -7929,6 +7936,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. */ @@ -8135,16 +8169,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, @@ -8156,7 +8192,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) @@ -8314,8 +8350,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 @@ -8561,7 +8630,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) @@ -8569,36 +8643,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. */ @@ -9706,6 +9810,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 7ac78847b3a..a88c6f917a6 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) @@ -1054,6 +1056,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 e35ce2de364..4898e3b8260 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 f137e1f17ef..d46459ff462 100644 --- a/gcc/config/riscv/t-riscv +++ b/gcc/config/riscv/t-riscv @@ -108,6 +108,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 b82497f00e4..d39d599ccb5 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -6227,8 +6227,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-warning-01.c b/gcc/testsuite/gcc.target/riscv/target-attr-warning-01.c new file mode 100644 index 00000000000..d4b6e4e505a --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/target-attr-warning-01.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-warning "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-warning-02.c b/gcc/testsuite/gcc.target/riscv/target-attr-warning-02.c new file mode 100644 index 00000000000..b43b131c955 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/target-attr-warning-02.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-warning "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-warning-03.c b/gcc/testsuite/gcc.target/riscv/target-attr-warning-03.c new file mode 100644 index 00000000000..551c56e37dc --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/target-attr-warning-03.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-warning "tune appears more than once" } */ +long foo(long a, long b){ + return a + (b * 2); +} -- 2.34.1