On Tue, Jul 16, 2024 at 1:09 AM Christoph Müllner
<christoph.muell...@vrull.eu> wrote:
>
> On Mon, Jul 15, 2024 at 11:10 AM Kito Cheng <kito.ch...@gmail.com> wrote:
> >
> > LGTM, and could you backport this to the GCC 14 branch as well?
>
> Rebased, retested (multilib), fixed an issue related to Zca/Zcd and pushed.
>
> Should the GCC 14 backport be posted for review before pushing?

I guess the patch for GCC 14 may little different than this patch
series since Pan's rewrite isn't applied on that,
however I trust you will handle this well, so pre-approved for that  :P

but don't forget to send committed patches to the mailing list (with
[committed][GCC-14] prefix in the title), so that we know you are done
:)




>
> Thanks,
> Christoph
>
> >
> > On Tue, Jul 9, 2024 at 8:50 PM Christoph Müllner
> > <christoph.muell...@vrull.eu> wrote:
> > >
> > > The target-arch attribute handling in RISC-V is only a few months old,
> > > but already saw a rewrite (9941f0295a14), which addressed an important
> > > issue.  This rewrite introduced a hash table in the backend, which is
> > > used to keep track of target-arch attributes of all functions.
> > > The index of this hash table is the pointer to the function declaration
> > > object (fndecl).  However, objects like these don't have the lifetime
> > > that is assumed here, which resulted in observing two fndecl objects
> > > with the same address for different objects (triggering the assertion
> > > in riscv_func_target_put() -- see also PR115562).
> > >
> > > This patch removes the hash table approach in favor of storing target
> > > specific options using the DECL_FUNCTION_SPECIFIC_TARGET() macro, which
> > > is also used by other backends and is specifically designed for this
> > > purpose (https://gcc.gnu.org/onlinedocs/gccint/Function-Properties.html).
> > >
> > > To have an accessible field in the target options, we need to
> > > adjust riscv.opt and introduce the field riscv_arch_string
> > > (for the already existing option '-march=').
> > >
> > > Using this macro allows to remove much code from riscv-common.cc, which
> > > controls access to the objects 'func_target_table' and 
> > > 'current_subset_list'.
> > >
> > > One thing to mention is, that we had two subset lists:
> > > current_subset_list and cmdline_subset_list, with the latter being
> > > introduced recently for target attribute handling.
> > > This patch reduces them back to one (cmdline_subset_list) which
> > > contains the list of extensions that have been enabled by the command
> > > line arguments.
> > >
> > > Note that the patch keeps the existing behavior of rejecting
> > > duplications of extensions when added via the '+' operator in a function
> > > target attribute.  E.g. "-march=rv64gc_zbb" and "arch=+zbb" will trigger
> > > an error (see pr115554.c).  However, at the same time this patch breaks
> > > the acceptance of adding implied extensions, which causes the following
> > > six regressions (with the error "extension 'EXT' appear more than one 
> > > time"):
> > > * gcc.target/riscv/rvv/base/target_attribute_v_with_intrinsic-39.c
> > > * gcc.target/riscv/rvv/base/target_attribute_v_with_intrinsic-42.c
> > > * gcc.target/riscv/rvv/base/target_attribute_v_with_intrinsic-43.c
> > > * gcc.target/riscv/rvv/base/target_attribute_v_with_intrinsic-44.c
> > > * gcc.target/riscv/rvv/base/target_attribute_v_with_intrinsic-45.c
> > > * gcc.target/riscv/rvv/base/target_attribute_v_with_intrinsic-46.c
> > >
> > > New tests were added to document the behavior and to ensure it won't
> > > regress.  This patch did not show any regressions for rv32/rv64
> > > and fixes the ICEs from PR115554 and PR115562.
> > >
> > >         PR 115554
> > >         PR 115562
> > >
> > > gcc/ChangeLog:
> > >
> > >         * common/config/riscv/riscv-common.cc (struct 
> > > riscv_func_target_info):
> > >         Remove.
> > >         (struct riscv_func_target_hasher): Likewise.
> > >         (riscv_func_decl_hash): Likewise.
> > >         (riscv_func_target_hasher::hash): Likewise.
> > >         (riscv_func_target_hasher::equal): Likewise.
> > >         (riscv_current_subset_list): Likewise.
> > >         (riscv_cmdline_subset_list): Remove obsolete space.
> > >         (riscv_func_target_table_lazy_init): Remove.
> > >         (riscv_func_target_get): Likewise.
> > >         (riscv_func_target_put): Likewise.
> > >         (riscv_func_target_remove_and_destory): Likewise.
> > >         (riscv_arch_str): Generate from cmdline_subset_list.
> > >         (riscv_set_arch_by_subset_list): Don't set current_subset_list.
> > >         (riscv_parse_arch_string): Remove current_subset_list.
> > >         * config/riscv/riscv-c.cc (riscv_cpu_cpp_builtins):
> > >         Get subset list via riscv_cmdline_subset_list().
> > >         * config/riscv/riscv-subset.h (riscv_current_subset_list):
> > >         Remove prototype.
> > >         (riscv_func_target_get): Likewise.
> > >         (riscv_func_target_put): Likewise.
> > >         (riscv_func_target_remove_and_destory): Likewise.
> > >         * config/riscv/riscv-target-attr.cc 
> > > (riscv_target_attr_parser::parse_arch):
> > >         Build base arch string from existing target options, if any.
> > >         (riscv_target_attr_parser::update_settings): Store new arch
> > >         string in target options.
> > >         (riscv_process_one_target_attr): Whitespace fix.
> > >         (riscv_process_target_attr): Drop opts argument.
> > >         (riscv_option_valid_attribute_p): Properly save, change and 
> > > restore
> > >         target options.
> > >         * config/riscv/riscv.cc (get_arch_str): New function.
> > >         (riscv_declare_function_name): Get arch string for option-arch
> > >         directive from function's target options.
> > >         * config/riscv/riscv.opt: Add riscv_arch_string variable to
> > >         march option.
> > >
> > > gcc/testsuite/ChangeLog:
> > >
> > >         * gcc.target/riscv/target-attr-01.c: Add test for option-arch 
> > > directive.
> > >         * gcc.target/riscv/target-attr-02.c: Likewise.
> > >         * gcc.target/riscv/target-attr-03.c: Likewise.
> > >         * gcc.target/riscv/target-attr-04.c: Likewise.
> > >         * gcc.target/riscv/target-attr-05.c: Fix formatting.
> > >         * gcc.target/riscv/target-attr-06.c: Likewise.
> > >         * gcc.target/riscv/target-attr-07.c: Likewise.
> > >         * gcc.target/riscv/pr115554.c: New test.
> > >         * gcc.target/riscv/pr115562.c: New test.
> > >         * gcc.target/riscv/target-attr-08.c: New test.
> > >         * gcc.target/riscv/target-attr-09.c: New test.
> > >         * gcc.target/riscv/target-attr-10.c: New test.
> > >         * gcc.target/riscv/target-attr-11.c: New test.
> > >         * gcc.target/riscv/target-attr-12.c: New test.
> > >         * gcc.target/riscv/target-attr-13.c: New test.
> > >         * gcc.target/riscv/target-attr-14.c: New test.
> > >         * gcc.target/riscv/target-attr-15.c: New test.
> > >
> > > Signed-off-by: Christoph Müllner <christoph.muell...@vrull.eu>
> > > ---
> > >  gcc/common/config/riscv/riscv-common.cc       | 113 +-----------------
> > >  gcc/config/riscv/riscv-c.cc                   |   2 +-
> > >  gcc/config/riscv/riscv-subset.h               |   4 -
> > >  gcc/config/riscv/riscv-target-attr.cc         | 102 +++++++++-------
> > >  gcc/config/riscv/riscv.cc                     |  22 ++--
> > >  gcc/config/riscv/riscv.opt                    |   2 +-
> > >  gcc/testsuite/gcc.target/riscv/pr115554.c     |  13 ++
> > >  gcc/testsuite/gcc.target/riscv/pr115562.c     |  25 ++++
> > >  .../gcc.target/riscv/target-attr-01.c         |  16 ++-
> > >  .../gcc.target/riscv/target-attr-02.c         |  16 ++-
> > >  .../gcc.target/riscv/target-attr-03.c         |  11 +-
> > >  .../gcc.target/riscv/target-attr-04.c         |  11 +-
> > >  .../gcc.target/riscv/target-attr-05.c         |  10 +-
> > >  .../gcc.target/riscv/target-attr-06.c         |  11 +-
> > >  .../gcc.target/riscv/target-attr-07.c         |  10 +-
> > >  .../gcc.target/riscv/target-attr-08.c         |  20 ++++
> > >  .../gcc.target/riscv/target-attr-09.c         |  19 +++
> > >  .../gcc.target/riscv/target-attr-10.c         |  19 +++
> > >  .../gcc.target/riscv/target-attr-11.c         |  22 ++++
> > >  .../gcc.target/riscv/target-attr-12.c         |  21 ++++
> > >  .../gcc.target/riscv/target-attr-13.c         |  21 ++++
> > >  .../gcc.target/riscv/target-attr-14.c         |  42 +++++++
> > >  .../gcc.target/riscv/target-attr-15.c         |  42 +++++++
> > >  23 files changed, 371 insertions(+), 203 deletions(-)
> > >  create mode 100644 gcc/testsuite/gcc.target/riscv/pr115554.c
> > >  create mode 100644 gcc/testsuite/gcc.target/riscv/pr115562.c
> > >  create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-08.c
> > >  create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-09.c
> > >  create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-10.c
> > >  create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-11.c
> > >  create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-12.c
> > >  create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-13.c
> > >  create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-14.c
> > >  create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-15.c
> > >
> > > diff --git a/gcc/common/config/riscv/riscv-common.cc 
> > > b/gcc/common/config/riscv/riscv-common.cc
> > > index dfe960e51293..c215484c287b 100644
> > > --- a/gcc/common/config/riscv/riscv-common.cc
> > > +++ b/gcc/common/config/riscv/riscv-common.cc
> > > @@ -438,110 +438,13 @@ static const char *riscv_supported_std_ext (void);
> > >
> > >  bool riscv_subset_list::parse_failed = false;
> > >
> > > -static riscv_subset_list *current_subset_list = NULL;
> > > -
> > >  static riscv_subset_list *cmdline_subset_list = NULL;
> > >
> > > -struct riscv_func_target_info
> > > -{
> > > -  tree fn_decl;
> > > -  std::string fn_target_name;
> > > -
> > > -  riscv_func_target_info (const tree &decl, const std::string 
> > > &target_name)
> > > -    : fn_decl (decl), fn_target_name (target_name)
> > > -  {
> > > -  }
> > > -};
> > > -
> > > -struct riscv_func_target_hasher : nofree_ptr_hash<struct 
> > > riscv_func_target_info>
> > > -{
> > > -  typedef tree compare_type;
> > > -
> > > -  static hashval_t hash (value_type);
> > > -  static bool equal (value_type, const compare_type &);
> > > -};
> > > -
> > > -static hash_table<riscv_func_target_hasher> *func_target_table = NULL;
> > > -
> > > -static inline hashval_t riscv_func_decl_hash (tree fn_decl)
> > > -{
> > > -  inchash::hash h;
> > > -
> > > -  h.add_ptr (fn_decl);
> > > -
> > > -  return h.end ();
> > > -}
> > > -
> > > -inline hashval_t
> > > -riscv_func_target_hasher::hash (value_type value)
> > > -{
> > > -  return riscv_func_decl_hash (value->fn_decl);
> > > -}
> > > -
> > > -inline bool
> > > -riscv_func_target_hasher::equal (value_type value, const compare_type 
> > > &key)
> > > -{
> > > -  return value->fn_decl == key;
> > > -}
> > > -
> > > -const riscv_subset_list *riscv_current_subset_list ()
> > > -{
> > > -  return current_subset_list;
> > > -}
> > > -
> > > -const riscv_subset_list * riscv_cmdline_subset_list ()
> > > +const riscv_subset_list *riscv_cmdline_subset_list ()
> > >  {
> > >    return cmdline_subset_list;
> > >  }
> > >
> > > -static inline void riscv_func_target_table_lazy_init ()
> > > -{
> > > -  if (func_target_table != NULL)
> > > -    return;
> > > -
> > > -  func_target_table = new hash_table<riscv_func_target_hasher> (1023);
> > > -}
> > > -
> > > -std::string * riscv_func_target_get (tree fn_decl)
> > > -{
> > > -  riscv_func_target_table_lazy_init ();
> > > -
> > > -  hashval_t hash = riscv_func_decl_hash (fn_decl);
> > > -  struct riscv_func_target_info *info
> > > -    = func_target_table->find_with_hash (fn_decl, hash);
> > > -
> > > -  return info == NULL ? NULL : &info->fn_target_name;
> > > -}
> > > -
> > > -void riscv_func_target_put (tree fn_decl, std::string fn_target_name)
> > > -{
> > > -  riscv_func_target_table_lazy_init ();
> > > -
> > > -  hashval_t hash = riscv_func_decl_hash (fn_decl);
> > > -  struct riscv_func_target_info **target_info_slot
> > > -    = func_target_table->find_slot_with_hash (fn_decl, hash, INSERT);
> > > -
> > > -  gcc_assert (!*target_info_slot);
> > > -
> > > -  struct riscv_func_target_info *info
> > > -    = new riscv_func_target_info (fn_decl, fn_target_name);
> > > -
> > > -  *target_info_slot = info;
> > > -}
> > > -
> > > -void riscv_func_target_remove_and_destory (tree fn_decl)
> > > -{
> > > -  hashval_t hash = riscv_func_decl_hash (fn_decl);
> > > -  struct riscv_func_target_info *info
> > > -    = func_target_table->find_with_hash (fn_decl, hash);
> > > -
> > > -  if (info)
> > > -    {
> > > -      func_target_table->remove_elt_with_hash (fn_decl, hash);
> > > -      delete info;
> > > -    }
> > > -}
> > > -
> > >  /* struct for recording multi-lib info.  */
> > >  struct riscv_multi_lib_info_t {
> > >    std::string path;
> > > @@ -1612,8 +1515,8 @@ riscv_subset_list::finalize ()
> > >  std::string
> > >  riscv_arch_str (bool version_p)
> > >  {
> > > -  if (current_subset_list)
> > > -    return current_subset_list->to_string (version_p);
> > > +  if (cmdline_subset_list)
> > > +    return cmdline_subset_list->to_string (version_p);
> > >    else
> > >      return std::string();
> > >  }
> > > @@ -1798,8 +1701,7 @@ static const riscv_ext_flag_table_t 
> > > riscv_ext_flag_table[] =
> > >    {NULL, NULL, 0}
> > >  };
> > >
> > > -/* Apply SUBSET_LIST to OPTS if OPTS is not null, also set 
> > > CURRENT_SUBSET_LIST
> > > -   to SUBSET_LIST, just note this WON'T delete old CURRENT_SUBSET_LIST.  
> > > */
> > > +/* Apply SUBSET_LIST to OPTS if OPTS is not null.  */
> > >
> > >  void
> > >  riscv_set_arch_by_subset_list (riscv_subset_list *subset_list,
> > > @@ -1826,8 +1728,6 @@ riscv_set_arch_by_subset_list (riscv_subset_list 
> > > *subset_list,
> > >             opts->*arch_ext_flag_tab->var_ref |= arch_ext_flag_tab->mask;
> > >         }
> > >      }
> > > -
> > > -  current_subset_list = subset_list;
> > >  }
> > >
> > >  /* Parse a RISC-V ISA string into an option mask.  Must clear or set all 
> > > arch
> > > @@ -1843,15 +1743,10 @@ riscv_parse_arch_string (const char *isa,
> > >    if (!subset_list)
> > >      return;
> > >
> > > -  /* Avoid double delete if current_subset_list equals 
> > > cmdline_subset_list.  */
> > > -  if (current_subset_list && current_subset_list != cmdline_subset_list)
> > > -    delete current_subset_list;
> > > -
> > >    if (cmdline_subset_list)
> > >      delete cmdline_subset_list;
> > >
> > >    cmdline_subset_list = subset_list;
> > > -  /* current_subset_list is set in the call below.  */
> > >
> > >    riscv_set_arch_by_subset_list (subset_list, opts);
> > >  }
> > > diff --git a/gcc/config/riscv/riscv-c.cc b/gcc/config/riscv/riscv-c.cc
> > > index 43c8eecbb6ff..71112d9c66d7 100644
> > > --- a/gcc/config/riscv/riscv-c.cc
> > > +++ b/gcc/config/riscv/riscv-c.cc
> > > @@ -218,7 +218,7 @@ riscv_cpu_cpp_builtins (cpp_reader *pfile)
> > >    /* Define architecture extension test macros.  */
> > >    builtin_define_with_int_value ("__riscv_arch_test", 1);
> > >
> > > -  const riscv_subset_list *subset_list = riscv_current_subset_list ();
> > > +  const riscv_subset_list *subset_list = riscv_cmdline_subset_list ();
> > >    if (!subset_list)
> > >      return;
> > >
> > > diff --git a/gcc/config/riscv/riscv-subset.h 
> > > b/gcc/config/riscv/riscv-subset.h
> > > index fe7f54d8bc57..256d28657460 100644
> > > --- a/gcc/config/riscv/riscv-subset.h
> > > +++ b/gcc/config/riscv/riscv-subset.h
> > > @@ -109,11 +109,7 @@ public:
> > >    void finalize ();
> > >  };
> > >
> > > -extern const riscv_subset_list *riscv_current_subset_list (void);
> > >  extern const riscv_subset_list *riscv_cmdline_subset_list (void);
> > > -extern std::string * riscv_func_target_get (tree);
> > > -extern void riscv_func_target_put (tree, std::string);
> > > -extern void riscv_func_target_remove_and_destory (tree);
> > >  extern void
> > >  riscv_set_arch_by_subset_list (riscv_subset_list *, struct gcc_options 
> > > *);
> > >
> > > diff --git a/gcc/config/riscv/riscv-target-attr.cc 
> > > b/gcc/config/riscv/riscv-target-attr.cc
> > > index 3d7753f64574..317806143949 100644
> > > --- a/gcc/config/riscv/riscv-target-attr.cc
> > > +++ b/gcc/config/riscv/riscv-target-attr.cc
> > > @@ -50,14 +50,6 @@ public:
> > >    bool handle_cpu (const char *);
> > >    bool handle_tune (const char *);
> > >
> > > -  void set_loc (location_t loc) {
> > > -    m_loc = loc;
> > > -  }
> > > -
> > > -  riscv_subset_list* get_riscv_subset_list () {
> > > -    return m_subset_list;
> > > -  }
> > > -
> > >    void update_settings (struct gcc_options *opts) const;
> > >  private:
> > >    const char *m_raw_attr_str;
> > > @@ -98,7 +90,7 @@ riscv_target_attr_parser::parse_arch (const char *str)
> > >    /* 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 ());
> > > +      m_subset_list = riscv_subset_list::parse (str, m_loc);
> > >
> > >        if (m_subset_list == nullptr)
> > >         goto fail;
> > > @@ -112,7 +104,10 @@ riscv_target_attr_parser::parse_arch (const char 
> > > *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_cmdline_subset_list ()->clone ();
> > > +      const char *local_arch_str = global_options.x_riscv_arch_string;
> > > +      m_subset_list = local_arch_str
> > > +                     ? riscv_subset_list::parse (local_arch_str, m_loc)
> > > +                     : riscv_cmdline_subset_list ()->clone ();
> > >        m_subset_list->set_loc (m_loc);
> > >        while (token)
> > >         {
> > > @@ -124,19 +119,18 @@ riscv_target_attr_parser::parse_arch (const char 
> > > *str)
> > >                 "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')
> > >             {
> > > -             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;
> > > -               }
> > > +             error_at (
> > > +               m_loc,
> > > +               "unexpected arch for %<target()%> attribute: bad "
> > > +               "string found %<%s%>", token);
> > > +             goto fail;
> > >             }
> > > +
> > >           token = strtok_r (NULL, ",", &str_to_check);
> > >         }
> > >
> > > @@ -216,7 +210,17 @@ 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);
> > > +    {
> > > +      std::string local_arch = m_subset_list->to_string (true);
> > > +      const char* local_arch_str = local_arch.c_str ();
> > > +      struct cl_target_option *default_opts
> > > +       = TREE_TARGET_OPTION (target_option_default_node);
> > > +      if (opts->x_riscv_arch_string != default_opts->x_riscv_arch_string)
> > > +       free (CONST_CAST (void *, (const void *) 
> > > opts->x_riscv_arch_string));
> > > +      opts->x_riscv_arch_string = xstrdup (local_arch_str);
> > > +
> > > +      riscv_set_arch_by_subset_list (m_subset_list, opts);
> > > +    }
> > >
> > >    if (m_cpu_info)
> > >      opts->x_riscv_cpu_string = m_cpu_info->name;
> > > @@ -272,8 +276,8 @@ riscv_process_one_target_attr (char *arg_str,
> > >
> > >        return (&attr_parser->*attr.handler) (arg);
> > >      }
> > > -  error_at (loc, "Got unknown attribute %<target(\"%s\")%>", 
> > > str_to_check);
> > >
> > > +  error_at (loc, "Got unknown attribute %<target(\"%s\")%>", 
> > > str_to_check);
> > >    return false;
> > >  }
> > >
> > > @@ -299,8 +303,7 @@ num_occurences_in_str (char c, char *str)
> > >     and update the global target options space.  */
> > >
> > >  static bool
> > > -riscv_process_target_attr (tree fndecl, tree args, location_t loc,
> > > -                          struct gcc_options *opts)
> > > +riscv_process_target_attr (tree args, location_t loc)
> > >  {
> > >    if (TREE_CODE (args) == TREE_LIST)
> > >      {
> > > @@ -309,7 +312,7 @@ riscv_process_target_attr (tree fndecl, tree args, 
> > > location_t loc,
> > >           tree head = TREE_VALUE (args);
> > >           if (head)
> > >             {
> > > -             if (!riscv_process_target_attr (fndecl, head, loc, opts))
> > > +             if (!riscv_process_target_attr (head, loc))
> > >                 return false;
> > >             }
> > >           args = TREE_CHAIN (args);
> > > @@ -323,6 +326,7 @@ riscv_process_target_attr (tree fndecl, tree args, 
> > > location_t loc,
> > >        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
> > > @@ -347,7 +351,9 @@ riscv_process_target_attr (tree fndecl, tree args, 
> > > location_t loc,
> > >    while (token)
> > >      {
> > >        num_attrs++;
> > > -      riscv_process_one_target_attr (token, loc, attr_parser);
> > > +      if (!riscv_process_one_target_attr (token, loc, attr_parser))
> > > +       return false;
> > > +
> > >        token = strtok_r (NULL, ";", &str_to_check);
> > >      }
> > >
> > > @@ -359,18 +365,16 @@ riscv_process_target_attr (tree fndecl, tree args, 
> > > location_t loc,
> > >      }
> > >
> > >    /* Apply settings from target attribute.  */
> > > -  attr_parser.update_settings (opts);
> > > -
> > > -  /* Add the string of the target attribute to the fndecl hash table.  */
> > > -  riscv_subset_list *subset_list = attr_parser.get_riscv_subset_list ();
> > > -  if (subset_list)
> > > -    riscv_func_target_put (fndecl, subset_list->to_string (true));
> > > +  attr_parser.update_settings (&global_options);
> > >
> > >    return true;
> > >  }
> > >
> > > -/* Implement TARGET_OPTION_VALID_ATTRIBUTE_P.  This is used to
> > > -   process attribute ((target ("..."))).  */
> > > +/* Implement TARGET_OPTION_VALID_ATTRIBUTE_P.
> > > +   This is used to process attribute ((target ("..."))).
> > > +   Note, that riscv_set_current_function() has not been called before,
> > > +   so we need must not mess with the current global_options, which
> > > +   likely belong to another function.  */
> > >
> > >  bool
> > >  riscv_option_valid_attribute_p (tree fndecl, tree, tree args, int)
> > > @@ -378,27 +382,39 @@ riscv_option_valid_attribute_p (tree fndecl, tree, 
> > > tree args, int)
> > >    struct cl_target_option cur_target;
> > >    bool ret;
> > >    tree new_target;
> > > +  tree existing_target = DECL_FUNCTION_SPECIFIC_TARGET (fndecl);
> > >    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 (fndecl, args, loc, &global_options);
> > > -
> > > -  if (ret)
> > > +  /* If fndecl already has some target attributes applied to it, unpack
> > > +     them so that we add this attribute on top of them, rather than
> > > +     overwriting them.  */
> > > +  if (existing_target)
> > >      {
> > > -      riscv_override_options_internal (&global_options);
> > > -      new_target
> > > -       = build_target_option_node (&global_options, &global_options_set);
> > > +      struct cl_target_option *existing_options
> > > +       = TREE_TARGET_OPTION (existing_target);
> > > +
> > > +      if (existing_options)
> > > +       cl_target_option_restore (&global_options, &global_options_set,
> > > +                                 existing_options);
> > >      }
> > >    else
> > > -    new_target = NULL;
> > > +    cl_target_option_restore (&global_options, &global_options_set,
> > > +                             TREE_TARGET_OPTION 
> > > (target_option_default_node));
> > >
> > > -  if (fndecl && ret)
> > > +  /* Now we can parse the attributes and set &global_options 
> > > accordingly.  */
> > > +  ret = riscv_process_target_attr (args, loc);
> > > +  if (ret)
> > >      {
> > > +      riscv_override_options_internal (&global_options);
> > > +      new_target = build_target_option_node (&global_options,
> > > +                                            &global_options_set);
> > >        DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = new_target;
> > >      }
> > >
> > > +  /* Restore current target options to original state.  */
> > >    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 38ed773c222d..d4766b6aeeee 100644
> > > --- a/gcc/config/riscv/riscv.cc
> > > +++ b/gcc/config/riscv/riscv.cc
> > > @@ -719,6 +719,15 @@ riscv_min_arithmetic_precision (void)
> > >    return 32;
> > >  }
> > >
> > > +/* Get the arch string from an options object.  */
> > > +
> > > +template <class T>
> > > +static const char *
> > > +get_arch_str (const T *opts)
> > > +{
> > > +  return opts->x_riscv_arch_string;
> > > +}
> > > +
> > >  template <class T>
> > >  static const char *
> > >  get_tune_str (const T *opts)
> > > @@ -9469,17 +9478,16 @@ riscv_declare_function_name (FILE *stream, const 
> > > char *name, tree fndecl)
> > >      {
> > >        fprintf (stream, "\t.option push\n");
> > >
> > > -      std::string *target_name = riscv_func_target_get (fndecl);
> > > -      std::string isa = target_name != NULL
> > > -       ? *target_name
> > > -       : riscv_cmdline_subset_list ()->to_string (true);
> > > -      fprintf (stream, "\t.option arch, %s\n", isa.c_str ());
> > > -      riscv_func_target_remove_and_destory (fndecl);
> > > -
> > >        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_arch_str = get_arch_str (local_cl_target);
> > > +      const char *arch_str = local_arch_str != NULL
> > > +       ? local_arch_str
> > > +       : riscv_arch_str (true).c_str ();
> > > +      fprintf (stream, "\t.option arch, %s\n", arch_str);
> > >        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)
> > > diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
> > > index 32a0dda58439..e882caa8b7f5 100644
> > > --- a/gcc/config/riscv/riscv.opt
> > > +++ b/gcc/config/riscv/riscv.opt
> > > @@ -82,7 +82,7 @@ Target Mask(DIV)
> > >  Use hardware instructions for integer division.
> > >
> > >  march=
> > > -Target RejectNegative Joined Negative(march=)
> > > +Target RejectNegative Joined Negative(march=) Var(riscv_arch_string) Save
> > >  -march=        Generate code for given RISC-V ISA (e.g. RV64IM).  ISA 
> > > strings must be
> > >  lower-case.
> > >
> > > diff --git a/gcc/testsuite/gcc.target/riscv/pr115554.c 
> > > b/gcc/testsuite/gcc.target/riscv/pr115554.c
> > > new file mode 100644
> > > index 000000000000..e7dcde6276fa
> > > --- /dev/null
> > > +++ b/gcc/testsuite/gcc.target/riscv/pr115554.c
> > > @@ -0,0 +1,13 @@
> > > +/* { dg-do compile } */
> > > +
> > > +extern
> > > +__attribute__((target("arch=+zba")))
> > > +__attribute__((target("arch=+zbb")))
> > > +void foo(void);
> > > +
> > > +extern
> > > +__attribute__((target("arch=+zbb")))
> > > +__attribute__((target("arch=+zbb")))
> > > +void bar(void);
> > > +
> > > +/* { dg-error "extension 'zbb' appear more than one time" "" { target 
> > > *-*-* } 0 } */
> > > diff --git a/gcc/testsuite/gcc.target/riscv/pr115562.c 
> > > b/gcc/testsuite/gcc.target/riscv/pr115562.c
> > > new file mode 100644
> > > index 000000000000..b20f69d8dec6
> > > --- /dev/null
> > > +++ b/gcc/testsuite/gcc.target/riscv/pr115562.c
> > > @@ -0,0 +1,25 @@
> > > +/* { dg-do compile } */
> > > +
> > > +void foo (void);
> > > +
> > > +__attribute__((target("arch=+zbb")))
> > > +void*
> > > +memcpy (void *d, const void *s, unsigned long n)
> > > +{
> > > +  (void) s;
> > > +  (void) n;
> > > +  return d;
> > > +}
> > > +__attribute__((target("arch=+zbb"))) void fun0(void) {}
> > > +__attribute__((target("arch=+zbb"))) void fun1(void) {}
> > > +__attribute__((target("arch=+zbb"))) void fun2(void) {}
> > > +__attribute__((target("arch=+zbb"))) void fun3(void) {}
> > > +__attribute__((target("arch=+zbb"))) void fun4(void) {}
> > > +__attribute__((target("arch=+zbb"))) void fun5(void) {}
> > > +__attribute__((target("arch=+zbb"))) void fun6(void) {}
> > > +__attribute__((target("arch=+zbb"))) void fun7(void) {}
> > > +__attribute__((target("arch=+zbb"))) void fun8(void) {}
> > > +__attribute__((target("arch=+zbb"))) void fun9(void) {}
> > > +__attribute__((target("arch=+zbb"))) void fun10(void) {}
> > > +__attribute__((target("arch=+zbb"))) void fun11(void) {}
> > > +__attribute__((target("arch=+zbb"))) void fun12(void) {}
> > > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-01.c 
> > > b/gcc/testsuite/gcc.target/riscv/target-attr-01.c
> > > index b3f3d65d543f..4748f6a08e72 100644
> > > --- a/gcc/testsuite/gcc.target/riscv/target-attr-01.c
> > > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-01.c
> > > @@ -1,19 +1,18 @@
> > >  /* { dg-do compile } */
> > > -/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> > > +/* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */
> > >  /* { 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){
> > > +/* { dg-final { scan-assembler ".option arch, 
> > > rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zaamo1p0_zalrsc1p0_zba1p0"
> > >  } } */
> > > +long foo () __attribute__((target("arch=rv64gc_zba")));
> > > +long foo (long a, long b)
> > > +{
> > >    return a + (b * 2);
> > >  }
> > >
> > > @@ -24,8 +23,7 @@ long foo(long a, long b){
> > >  **   add\s*a0,a1,a0
> > >  **   ...
> > >  */
> > > -
> > > -
> > > -long bar(long a, long b){
> > > +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
> > > index c010089a823b..9ebf16e3675e 100644
> > > --- a/gcc/testsuite/gcc.target/riscv/target-attr-02.c
> > > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-02.c
> > > @@ -1,19 +1,18 @@
> > >  /* { dg-do compile } */
> > > -/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> > > +/* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */
> > >  /* { 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){
> > > +/* { dg-final { scan-assembler ".option arch, 
> > > rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zaamo1p0_zalrsc1p0_zba1p0"
> > >  } } */
> > > +long foo () __attribute__((target("arch=+zba")));
> > > +long foo (long a, long b)
> > > +{
> > >    return a + (b * 2);
> > >  }
> > >
> > > @@ -24,8 +23,7 @@ long foo(long a, long b){
> > >  **   add\s*a0,a1,a0
> > >  **   ...
> > >  */
> > > -
> > > -
> > > -long bar(long a, long b){
> > > +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
> > > index b4896cb2e277..44fabf68fd07 100644
> > > --- a/gcc/testsuite/gcc.target/riscv/target-attr-03.c
> > > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-03.c
> > > @@ -1,5 +1,5 @@
> > >  /* { dg-do compile } */
> > > -/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> > > +/* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */
> > >  /* { dg-options "-march=rv64gc_zba -O2 -mabi=lp64" } */
> > >  /* { dg-final { check-function-bodies "**" "" } } */
> > >
> > > @@ -10,8 +10,10 @@
> > >  **   add\s*a0,a1,a0
> > >  **   ...
> > >  */
> > > -long foo() __attribute__((target("arch=rv64gc")));
> > > -long foo(long a, long b){
> > > +/* { dg-final { scan-assembler ".option arch, 
> > > rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zaamo1p0_zalrsc1p0"
> > >  } } */
> > > +long foo () __attribute__((target("arch=rv64gc")));
> > > +long foo (long a, long b)
> > > +{
> > >    return a + (b * 2);
> > >  }
> > >
> > > @@ -21,6 +23,7 @@ long foo(long a, long b){
> > >  **   sh1add\s*a0,a1,a0
> > >  **   ...
> > >  */
> > > -long bar(long a, long b){
> > > +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
> > > index 369d6514e5aa..258eaf4eb584 100644
> > > --- a/gcc/testsuite/gcc.target/riscv/target-attr-04.c
> > > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-04.c
> > > @@ -1,5 +1,5 @@
> > >  /* { dg-do compile } */
> > > -/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> > > +/* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */
> > >  /* { dg-options "-march=rv64gc_zba -O2 -mabi=lp64 -mtune=rocket" } */
> > >  /* { dg-final { check-function-bodies "**" "" } } */
> > >
> > > @@ -12,8 +12,10 @@
> > >  **   add\s*a0,a1,a0
> > >  **   ...
> > >  */
> > > -long foo() __attribute__((target("cpu=sifive-u74")));
> > > -long foo(long a, long b){
> > > +/* { dg-final { scan-assembler ".option arch, 
> > > rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zaamo1p0_zalrsc1p0" } } */
> > > +long foo () __attribute__((target("cpu=sifive-u74")));
> > > +long foo (long a, long b)
> > > +{
> > >    return a + (b * 2);
> > >  }
> > >
> > > @@ -23,6 +25,7 @@ long foo(long a, long b){
> > >  **   sh1add\s*a0,a1,a0
> > >  **   ...
> > >  */
> > > -long bar(long a, long b){
> > > +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
> > > index c75368dcebf9..1474f319e414 100644
> > > --- a/gcc/testsuite/gcc.target/riscv/target-attr-05.c
> > > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-05.c
> > > @@ -1,5 +1,5 @@
> > >  /* { dg-do compile } */
> > > -/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> > > +/* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */
> > >  /* { dg-options "-march=rv64gc_zba -O2 -mabi=lp64 -mtune=rocket" } */
> > >  /* { dg-final { check-function-bodies "**" "" } } */
> > >
> > > @@ -11,8 +11,9 @@
> > >  **   sh1add\s*a0,a1,a0
> > >  **   ...
> > >  */
> > > -long foo() __attribute__((target("cpu=sifive-u74;arch=rv64gc_zba")));
> > > -long foo(long a, long b){
> > > +long foo () __attribute__((target("cpu=sifive-u74;arch=rv64gc_zba")));
> > > +long foo (long a, long b)
> > > +{
> > >    return a + (b * 2);
> > >  }
> > >
> > > @@ -22,6 +23,7 @@ long foo(long a, long b){
> > >  **   sh1add\s*a0,a1,a0
> > >  **   ...
> > >  */
> > > -long bar(long a, long b){
> > > +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
> > > index 369c95eeb54b..32ecfaee319a 100644
> > > --- a/gcc/testsuite/gcc.target/riscv/target-attr-06.c
> > > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-06.c
> > > @@ -1,5 +1,5 @@
> > >  /* { dg-do compile } */
> > > -/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> > > +/* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */
> > >  /* { dg-options "-march=rv64gc_zba -O2 -mabi=lp64 -mtune=rocket" } */
> > >  /* { dg-final { check-function-bodies "**" "" } } */
> > >
> > > @@ -11,8 +11,10 @@
> > >  **   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){
> > > +long foo ()
> > > +__attribute__((target("cpu=sifive-u74;tune=sifive-5-series;arch=rv64gc_zba")));
> > > +long foo (long a, long b)
> > > +{
> > >    return a + (b * 2);
> > >  }
> > >
> > > @@ -22,6 +24,7 @@ long foo(long a, long b){
> > >  **   sh1add\s*a0,a1,a0
> > >  **   ...
> > >  */
> > > -long bar(long a, long b){
> > > +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
> > > index 4ff81166a626..f3066f4fcfea 100644
> > > --- a/gcc/testsuite/gcc.target/riscv/target-attr-07.c
> > > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-07.c
> > > @@ -1,5 +1,5 @@
> > >  /* { dg-do compile } */
> > > -/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
> > > +/* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */
> > >  /* { dg-options "-march=rv64gc_zba -O2 -mabi=lp64 -mtune=rocket" } */
> > >  /* { dg-final { check-function-bodies "**" "" } } */
> > >
> > > @@ -9,8 +9,9 @@
> > >  **   # tune = sifive-5-series
> > >  **   ...
> > >  */
> > > -long foo() __attribute__((target("tune=sifive-5-series")));
> > > -long foo(long a, long b){
> > > +long foo () __attribute__((target("tune=sifive-5-series")));
> > > +long foo (long a, long b)
> > > +{
> > >    return a + (b * 2);
> > >  }
> > >
> > > @@ -20,6 +21,7 @@ long foo(long a, long b){
> > >  **   sh1add\s*a0,a1,a0
> > >  **   ...
> > >  */
> > > -long bar(long a, long b){
> > > +long bar (long a, long b)
> > > +{
> > >    return a + (b * 2);
> > >  }
> > > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-08.c 
> > > b/gcc/testsuite/gcc.target/riscv/target-attr-08.c
> > > new file mode 100644
> > > index 000000000000..e7792c1598e4
> > > --- /dev/null
> > > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-08.c
> > > @@ -0,0 +1,20 @@
> > > +/* { dg-do compile } */
> > > +/* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */
> > > +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> > > +/* { dg-final { check-function-bodies "**" "" } } */
> > > +
> > > +long foo ()
> > > +__attribute__((target("arch=rv64gc_zbb")))
> > > +__attribute__((target("arch=rv64gc_zba")));
> > > +
> > > +/*
> > > +** foo:
> > > +**   ...
> > > +**   sh1add\s*a0,a1,a0
> > > +**   ...
> > > +*/
> > > +/* { dg-final { scan-assembler ".option arch, 
> > > rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zaamo1p0_zalrsc1p0_zba1p0"
> > >  } } */
> > > +long foo (long a, long b)
> > > +{
> > > +  return a + (b * 2);
> > > +}
> > > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-09.c 
> > > b/gcc/testsuite/gcc.target/riscv/target-attr-09.c
> > > new file mode 100644
> > > index 000000000000..ec43ce95998b
> > > --- /dev/null
> > > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-09.c
> > > @@ -0,0 +1,19 @@
> > > +/* { dg-do compile } */
> > > +/* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */
> > > +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> > > +/* { dg-final { check-function-bodies "**" "" } } */
> > > +
> > > +long foo ()
> > > +__attribute__((target("cpu=sifive-e20")))
> > > +__attribute__((target("cpu=sifive-u74")));
> > > +
> > > +/*
> > > +** foo:
> > > +**   ...
> > > +**   # tune = sifive-7-series
> > > +**   ...
> > > +*/
> > > +long foo (long a, long b)
> > > +{
> > > +  return a + (b * 2);
> > > +}
> > > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-10.c 
> > > b/gcc/testsuite/gcc.target/riscv/target-attr-10.c
> > > new file mode 100644
> > > index 000000000000..86a79c7d6ccf
> > > --- /dev/null
> > > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-10.c
> > > @@ -0,0 +1,19 @@
> > > +/* { dg-do compile } */
> > > +/* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */
> > > +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> > > +/* { dg-final { check-function-bodies "**" "" } } */
> > > +
> > > +long foo ()
> > > +__attribute__((target("tune=rocket")))
> > > +__attribute__((target("tune=sifive-u74")));
> > > +
> > > +/*
> > > +** foo:
> > > +**   ...
> > > +**   # tune = sifive-7-series
> > > +**   ...
> > > +*/
> > > +long foo (long a, long b)
> > > +{
> > > +  return a + (b * 2);
> > > +}
> > > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-11.c 
> > > b/gcc/testsuite/gcc.target/riscv/target-attr-11.c
> > > new file mode 100644
> > > index 000000000000..6e02a98f1206
> > > --- /dev/null
> > > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-11.c
> > > @@ -0,0 +1,22 @@
> > > +/* { dg-do compile } */
> > > +/* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */
> > > +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> > > +/* { dg-final { check-function-bodies "**" "" } } */
> > > +
> > > +long foo ()
> > > +__attribute__((target("arch=rv64gc_zbb")));
> > > +
> > > +long foo ()
> > > +__attribute__((target("arch=rv64gc_zba")));
> > > +
> > > +/*
> > > +** foo:
> > > +**   ...
> > > +**   sh1add\s*a0,a1,a0
> > > +**   ...
> > > +*/
> > > +/* { dg-final { scan-assembler ".option arch, 
> > > rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zaamo1p0_zalrsc1p0_zba1p0"
> > >  } } */
> > > +long foo (long a, long b)
> > > +{
> > > +  return a + (b * 2);
> > > +}
> > > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-12.c 
> > > b/gcc/testsuite/gcc.target/riscv/target-attr-12.c
> > > new file mode 100644
> > > index 000000000000..e0f8eafa040a
> > > --- /dev/null
> > > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-12.c
> > > @@ -0,0 +1,21 @@
> > > +/* { dg-do compile } */
> > > +/* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */
> > > +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> > > +/* { dg-final { check-function-bodies "**" "" } } */
> > > +
> > > +long foo ()
> > > +__attribute__((target("cpu=sifive-e20")));
> > > +
> > > +long foo ()
> > > +__attribute__((target("cpu=sifive-u74")));
> > > +
> > > +/*
> > > +** foo:
> > > +**   ...
> > > +**   # tune = sifive-7-series
> > > +**   ...
> > > +*/
> > > +long foo (long a, long b)
> > > +{
> > > +  return a + (b * 2);
> > > +}
> > > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-13.c 
> > > b/gcc/testsuite/gcc.target/riscv/target-attr-13.c
> > > new file mode 100644
> > > index 000000000000..0a26111956b9
> > > --- /dev/null
> > > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-13.c
> > > @@ -0,0 +1,21 @@
> > > +/* { dg-do compile } */
> > > +/* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */
> > > +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> > > +/* { dg-final { check-function-bodies "**" "" } } */
> > > +
> > > +long foo ()
> > > +__attribute__((target("tune=rocket")));
> > > +
> > > +long foo ()
> > > +__attribute__((target("tune=sifive-u74")));
> > > +
> > > +/*
> > > +** foo:
> > > +**   ...
> > > +**   # tune = sifive-7-series
> > > +**   ...
> > > +*/
> > > +long foo (long a, long b)
> > > +{
> > > +  return a + (b * 2);
> > > +}
> > > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-14.c 
> > > b/gcc/testsuite/gcc.target/riscv/target-attr-14.c
> > > new file mode 100644
> > > index 000000000000..59de060eec38
> > > --- /dev/null
> > > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-14.c
> > > @@ -0,0 +1,42 @@
> > > +/* { dg-do compile } */
> > > +/* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */
> > > +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> > > +/* { dg-final { check-function-bodies "**" "" } } */
> > > +
> > > +/*
> > > +** foo:
> > > +**   ...
> > > +**   sh1add\s*a0,a1,a0
> > > +**   ...
> > > +*/
> > > +/* { dg-final { scan-assembler ".option arch, 
> > > rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zaamo1p0_zalrsc1p0_zba1p0"
> > >  } } */
> > > +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);
> > > +}
> > > +
> > > +/*
> > > +** foo_th:
> > > +**   ...
> > > +**   th.addsl\s*a0,a0,a1,1
> > > +**   ...
> > > +*/
> > > +/* { dg-final { scan-assembler ".option arch, 
> > > rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zaamo1p0_zalrsc1p0_xtheadba1p0"
> > >  } } */
> > > +long foo_th () __attribute__((target("arch=rv64gc_xtheadba")));
> > > +long foo_th (long a, long b)
> > > +{
> > > +  return a + (b * 2);
> > > +}
> > > diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-15.c 
> > > b/gcc/testsuite/gcc.target/riscv/target-attr-15.c
> > > new file mode 100644
> > > index 000000000000..5120ad7b1d62
> > > --- /dev/null
> > > +++ b/gcc/testsuite/gcc.target/riscv/target-attr-15.c
> > > @@ -0,0 +1,42 @@
> > > +/* { dg-do compile } */
> > > +/* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */
> > > +/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
> > > +/* { dg-final { check-function-bodies "**" "" } } */
> > > +
> > > +/*
> > > +** foo:
> > > +**   ...
> > > +**   sh1add\s*a0,a1,a0
> > > +**   ...
> > > +*/
> > > +/* { dg-final { scan-assembler ".option arch, 
> > > rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zaamo1p0_zalrsc1p0_zba1p0"
> > >  } } */
> > > +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);
> > > +}
> > > +
> > > +/*
> > > +** foo_th:
> > > +**   ...
> > > +**   th.addsl\s*a0,a0,a1,1
> > > +**   ...
> > > +*/
> > > +/* { dg-final { scan-assembler ".option arch, 
> > > rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zaamo1p0_zalrsc1p0_xtheadba1p0"
> > >  } } */
> > > +long foo_th () __attribute__((target("arch=+xtheadba")));
> > > +long foo_th (long a, long b)
> > > +{
> > > +  return a + (b * 2);
> > > +}
> > > --
> > > 2.45.2
> > >

Reply via email to