ewlu / gcc-precommit-ci

2 stars 0 forks source link

Patch Status 36279-committedGCC14_RISCV_Rewrite_target_attribute_handling-1 #1915

Closed github-actions[bot] closed 3 months ago

github-actions[bot] commented 3 months ago

Precommit CI Run information

Logs can be found in the associated Github Actions run: https://github.com/ewlu/gcc-precommit-ci/actions/runs/9956126422

Patch information

Applied patches: 1 -> 1 Associated series: https://patchwork.sourceware.org/project/gcc/list/?series=36279 Last patch applied: https://patchwork.sourceware.org/project/gcc/patch/20240716111815.129028-4-christoph.muellner@vrull.eu/ Patch id: 93975

Build Targets

Some targets are built as multilibs. If a build target ends with multilib, please refer to the table below to see all the targets within that multilib. Target name -march string
newlib-rv64gc-lp64d-multilib rv32gc-ilp32d, rv64gc-lp64d
newlib-rv64gcv-lp64d-multilib rv64gcv-lp64d
linux-rv64gcv-lp64d-multilib rv32gcv-ilp32d, rv64gcv-lp64d

Target Information

Target Shorthand -march string
Bitmanip gc_zba_zbb_zbc_zbs

Notes

Testsuite results use a more lenient allowlist to reduce error reporting with flakey tests. Please take a look at the current allowlist. Results come from a sum file comparator. Each patch is applied to a well known, non-broken baseline taken from our gcc postcommit framework (here) which runs the full gcc testsuite every 6 hours. If you have any questions or encounter any issues which may seem like false-positives, please contact us at patchworks-ci@rivosinc.com

github-actions[bot] commented 3 months ago

Lint Status

The following issues have been found with 36279-committedGCC14_RISCV_Rewrite_target_attribute_handling-1 using gcc's ./contrib/check_GNU_style.py. Please use your best judgement when resolving these issues. These are only warnings and do not need to be resolved in order to merge your patch.

=== ERROR type #1: there should be exactly one space between function name and parenthesis (4 error(s)) ===
gcc/config/riscv/riscv-target-attr.cc:130:31:       "unexpected arch for %<target()%> attribute: bad "
gcc/config/riscv/riscv-target-attr.cc:282:48:  error_at (loc, "Got unknown attribute %<target(\"%s\")%>", str_to_check);
gcc/config/riscv/riscv-target-attr.cc:378:40:   Note, that riscv_set_current_function() has not been called before,
gcc/config/riscv/riscv.opt:85:37:Target RejectNegative Joined Negative(march=) Var(riscv_arch_string) Save

Additional information

github-actions[bot] commented 3 months ago

Apply Status

Target Status
Baseline hash: https://github.com/gcc-mirror/gcc/commit/c6803cdaba7a7bf933e52cd36f901430253cc2b0 Failed
Tip of tree hash: https://github.com/gcc-mirror/gcc/commit/acd4ab8d6e8938d48e74ad04adf22ece280e35c0 Failed

Command

> git am ../patches/*.patch --whitespace=fix -q --3way --empty=drop

Output

error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch=diff' to see the failed patch
hint: When you have resolved this problem, run "git am --continue".
hint: If you prefer to skip this patch, run "git am --skip" instead.
hint: To restore the original branch and stop patching, run "git am --abort".
hint: Disable this message with "git config advice.mergeConflict false"
Patch failed at 0001 RISC-V: Rewrite target attribute handling
---
 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 cc43c8dd6b4..2257b959acb 100644
--- a/gcc/common/config/riscv/riscv-common.cc
+++ b/gcc/common/config/riscv/riscv-common.cc
@@ -424,110 +424,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;
@@ -1579,8 +1482,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();
 }
@@ -1759,8 +1662,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,
@@ -1787,8 +1689,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
@@ -1804,15 +1704,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 43c8eecbb6f..71112d9c66d 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 fe7f54d8bc5..256d2865746 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 0bbe7df25d1..b514e68bf40 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;
@@ -113,7 +105,10 @@ riscv_target_attr_parser::parse_arch (const char *str)
       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_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)
    {
@@ -125,19 +120,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);
    }

@@ -217,7 +211,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;
@@ -274,8 +278,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;
 }

@@ -301,8 +305,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)
     {
@@ -311,7 +314,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);
@@ -325,6 +328,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
@@ -350,7 +354,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);
     }

@@ -362,18 +368,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)
@@ -381,27 +385,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 8aa34267c99..8e920412e6f 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -681,6 +681,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)
@@ -8962,17 +8971,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 b14888e9816..73de2eda31e 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 00000000000..e7dcde6276f
--- /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 00000000000..b20f69d8dec
--- /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 b3f3d65d543..1bf108e9d72 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_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 c010089a823..3d0c8a72f59 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_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 b4896cb2e27..1cba2c25744 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" } } */
+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 369d6514e5a..1193dcfa30e 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" } } */
+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 c75368dcebf..1474f319e41 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 369c95eeb54..32ecfaee319 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 4ff81166a62..f3066f4fcfe 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 00000000000..43c7141139e
--- /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_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 00000000000..ec43ce95998
--- /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 00000000000..86a79c7d6cc
--- /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 00000000000..b79e6de6468
--- /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_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 00000000000..e0f8eafa040
--- /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 00000000000..0a26111956b
--- /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 00000000000..ad42c389287
--- /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_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_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 00000000000..586cc581c86
--- /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_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_xtheadba1p0" } } */
+long foo_th () __attribute__((target("arch=+xtheadba")));
+long foo_th (long a, long b)
+{
+  return a + (b * 2);
+}

Additional information