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
> >

Reply via email to