public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* (no subject)
@ 2023-10-03  9:09 Kito Cheng
  2023-10-03  9:09 ` [PATCH v1 1/4] options: Define TARGET_<NAME>_P and TARGET_<NAME>_OPTS_P macro for Mask and InverseMask Kito Cheng
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: Kito Cheng @ 2023-10-03  9:09 UTC (permalink / raw)
  To: gcc-patches, kito.cheng, palmer, jeffreyalaw, rdapp, juzhe.zhong

From: Kito Cheng <kito.cheng@sifive.com>

Reply-To:

Subject: [PATCH v1 0/4] RISC-V target attribute

In-Reply-To:

This patch set implement target attribute for RISC-V target, which is similar to other target like x86 or ARM, let user able to set some local setting per function without changing global settings.

We support arch, tune and cpu first, and we will support other target attribute later, this version DOES NOT include multi-version function support yet, that is future work, probably work for GCC 15.

The full proposal is put in RISC-V C-API document[1], which has discussed with RISC-V LLVM community, so we have consistent syntax and semantics. 

[1] https://github.com/riscv-non-isa/riscv-c-api-doc/pull/35



^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v1 1/4] options: Define TARGET_<NAME>_P and TARGET_<NAME>_OPTS_P macro for Mask and InverseMask
  2023-10-03  9:09 Kito Cheng
@ 2023-10-03  9:09 ` Kito Cheng
  2023-10-09 14:16   ` Jeff Law
  2023-10-03  9:09 ` [PATCH v1 2/4] RISC-V: Refactor riscv_option_override and riscv_convert_vector_bits. [NFC] Kito Cheng
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 9+ messages in thread
From: Kito Cheng @ 2023-10-03  9:09 UTC (permalink / raw)
  To: gcc-patches, kito.cheng, palmer, jeffreyalaw, rdapp, juzhe.zhong
  Cc: Kito Cheng

We TARGET_<NAME>_P marcro to test a Mask and InverseMask with user
specified target_variable, however we may want to test with specific
gcc_options variable rather than target_variable.

Like RISC-V has defined lots of Mask with TargetVariable, which is not
easy to use, because that means we need to known which Mask are associate with
which TargetVariable, so take a gcc_options variable is a better interface
for such use case.

gcc/ChangeLog:

	* doc/options.texi (Mask): Document TARGET_<NAME>_P and
	TARGET_<NAME>_OPTS_P.
	(InverseMask): Ditto.
	* opth-gen.awk (Mask): Generate TARGET_<NAME>_P and
	TARGET_<NAME>_OPTS_P macro.
	(InverseMask): Ditto.
---
 gcc/doc/options.texi | 23 ++++++++++++++++-------
 gcc/opth-gen.awk     | 13 ++++++++++++-
 2 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/gcc/doc/options.texi b/gcc/doc/options.texi
index 1f7c15b8eb4..715f0a1479c 100644
--- a/gcc/doc/options.texi
+++ b/gcc/doc/options.texi
@@ -404,18 +404,27 @@ You may also specify @code{Var} to select a variable other than
 The options-processing script will automatically allocate a unique bit
 for the option.  If the option is attached to @samp{target_flags} or @code{Var}
 which is defined by @code{TargetVariable},  the script will set the macro
-@code{MASK_@var{name}} to the appropriate bitmask.  It will also declare a 
-@code{TARGET_@var{name}} macro that has the value 1 when the option is active
-and 0 otherwise.  If you use @code{Var} to attach the option to a different variable
-which is not defined by @code{TargetVariable}, the bitmask macro with be
-called @code{OPTION_MASK_@var{name}}.
+@code{MASK_@var{name}} to the appropriate bitmask.  It will also declare a
+@code{TARGET_@var{name}}, @code{TARGET_@var{name}_P} and
+@code{TARGET_@var{name}_OPTS_P}: @code{TARGET_@var{name}} macros that has the
+value 1 when the option is active and 0 otherwise, @code{TARGET_@var{name}_P} is
+similar to @code{TARGET_@var{name}} but take an argument as @samp{target_flags}
+or @code{TargetVariable}, and @code{TARGET_@var{name}_OPTS_P} also similar to
+@code{TARGET_@var{name}} but take an argument as @code{gcc_options}.
+If you use @code{Var} to attach the option to a different variable which is not
+defined by @code{TargetVariable}, the bitmask macro with be called
+@code{OPTION_MASK_@var{name}}.
 
 @item InverseMask(@var{othername})
 @itemx InverseMask(@var{othername}, @var{thisname})
 The option is the inverse of another option that has the
 @code{Mask(@var{othername})} property.  If @var{thisname} is given,
-the options-processing script will declare a @code{TARGET_@var{thisname}}
-macro that is 1 when the option is active and 0 otherwise.
+the options-processing script will declare @code{TARGET_@var{thisname}},
+@code{TARGET_@var{name}_P} and @code{TARGET_@var{name}_OPTS_P} macros:
+@code{TARGET_@var{thisname}} is 1 when the option is active and 0 otherwise,
+@code{TARGET_@var{name}_P} is similar to @code{TARGET_@var{name}} but take an
+argument as @samp{target_flags}, and and @code{TARGET_@var{name}_OPTS_P} also
+similar to @code{TARGET_@var{name}} but take an argument as @code{gcc_options}.
 
 @item Enum(@var{name})
 The option's argument is a string from the set of strings associated
diff --git a/gcc/opth-gen.awk b/gcc/opth-gen.awk
index 70ca3d37719..4d498abd130 100644
--- a/gcc/opth-gen.awk
+++ b/gcc/opth-gen.awk
@@ -439,6 +439,10 @@ for (i = 0; i < n_target_vars; i++)
 	{
 		print "#define TARGET_" other_masks[i][j] \
 		      " ((" target_vars[i] " & MASK_" other_masks[i][j] ") != 0)"
+		print "#define TARGET_" other_masks[i][j] "_P(" target_vars[i] ")" \
+		      " (((" target_vars[i] ") & MASK_" other_masks[i][j] ") != 0)"
+		print "#define TARGET_" other_masks[i][j] "_OPTS_P(opts)" \
+		      " (((opts->x_" target_vars[i] ") & MASK_" other_masks[i][j] ") != 0)"
 	}
 }
 print ""
@@ -469,15 +473,22 @@ for (i = 0; i < n_opts; i++) {
 		      " ((" vname " & " mask original_name ") != 0)"
 		print "#define TARGET_" name "_P(" vname ")" \
 		      " (((" vname ") & " mask original_name ") != 0)"
+		print "#define TARGET_" name "_OPTS_P(opts)" \
+		      " (((opts->x_" vname ") & " mask original_name ") != 0)"
 		print "#define TARGET_EXPLICIT_" name "_P(opts)" \
 		      " ((opts->x_" vname "_explicit & " mask original_name ") != 0)"
 		print "#define SET_TARGET_" name "(opts) opts->x_" vname " |= " mask original_name
 	}
 }
 for (i = 0; i < n_extra_masks; i++) {
-	if (extra_mask_macros[extra_masks[i]] == 0)
+	if (extra_mask_macros[extra_masks[i]] == 0) {
 		print "#define TARGET_" extra_masks[i] \
 		      " ((target_flags & MASK_" extra_masks[i] ") != 0)"
+		print "#define TARGET_" extra_masks[i] "_P(target_flags)" \
+		      " (((target_flags) & " extra_masks[i] ") != 0)"
+		print "#define TARGET_" extra_masks[i] "_OPTS_P(opts)" \
+		      " (((opts->x_target_flags) & MASK_" extra_masks[i] ") != 0)"
+	}
 }
 print ""
 
-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v1 2/4] RISC-V: Refactor riscv_option_override and riscv_convert_vector_bits. [NFC]
  2023-10-03  9:09 Kito Cheng
  2023-10-03  9:09 ` [PATCH v1 1/4] options: Define TARGET_<NAME>_P and TARGET_<NAME>_OPTS_P macro for Mask and InverseMask Kito Cheng
@ 2023-10-03  9:09 ` Kito Cheng
  2023-10-09 14:18   ` Jeff Law
  2023-10-03  9:09 ` [PATCH v1 3/4] RISC-V: Extend riscv_subset_list, preparatory for target attribute support Kito Cheng
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 9+ messages in thread
From: Kito Cheng @ 2023-10-03  9:09 UTC (permalink / raw)
  To: gcc-patches, kito.cheng, palmer, jeffreyalaw, rdapp, juzhe.zhong
  Cc: Kito Cheng

Allow those funciton apply from a local gcc_options rather than the
global options.

Preparatory for target attribute, sperate this change for eaiser reivew
since it's a NFC.

gcc/ChangeLog:

	* config/riscv/riscv.cc (riscv_convert_vector_bits): Get setting
	from argument rather than get setting from global setting.
	(riscv_override_options_internal): New, splited from
	riscv_override_options, also take a gcc_options argument.
	(riscv_option_override): Splited most part to
	riscv_override_options_internal.
---
 gcc/config/riscv/riscv.cc | 93 ++++++++++++++++++++++-----------------
 1 file changed, 52 insertions(+), 41 deletions(-)

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index d5446b63dbf..d089ec1b241 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -7982,10 +7982,11 @@ riscv_init_machine_status (void)
 /* Return the VLEN value associated with -march.
    TODO: So far we only support length-agnostic value. */
 static poly_uint16
-riscv_convert_vector_bits (void)
+riscv_convert_vector_bits (struct gcc_options *opts)
 {
   int chunk_num;
-  if (TARGET_MIN_VLEN > 32)
+  int min_vlen = TARGET_MIN_VLEN_OPTS (opts);
+  if (min_vlen > 32)
     {
       /* When targetting minimum VLEN > 32, we should use 64-bit chunk size.
 	 Otherwise we can not include SEW = 64bits.
@@ -8003,7 +8004,7 @@ riscv_convert_vector_bits (void)
 	   - TARGET_MIN_VLEN = 2048bit: [256,256]
 	   - TARGET_MIN_VLEN = 4096bit: [512,512]
 	   FIXME: We currently DON'T support TARGET_MIN_VLEN > 4096bit.  */
-      chunk_num = TARGET_MIN_VLEN / 64;
+      chunk_num = min_vlen / 64;
     }
   else
     {
@@ -8022,10 +8023,10 @@ riscv_convert_vector_bits (void)
      to set RVV mode size. The RVV machine modes size are run-time constant if
      TARGET_VECTOR is enabled. The RVV machine modes size remains default
      compile-time constant if TARGET_VECTOR is disabled.  */
-  if (TARGET_VECTOR)
+  if (TARGET_VECTOR_OPTS_P (opts))
     {
-      if (riscv_autovec_preference == RVV_FIXED_VLMAX)
-	return (int) TARGET_MIN_VLEN / (riscv_bytes_per_vector_chunk * 8);
+      if (opts->x_riscv_autovec_preference == RVV_FIXED_VLMAX)
+	return (int) min_vlen / (riscv_bytes_per_vector_chunk * 8);
       else
 	return poly_uint16 (chunk_num, chunk_num);
     }
@@ -8033,40 +8034,33 @@ riscv_convert_vector_bits (void)
     return 1;
 }
 
-/* Implement TARGET_OPTION_OVERRIDE.  */
-
-static void
-riscv_option_override (void)
+/* 'Unpack' up the internal tuning structs and update the options
+    in OPTS.  The caller must have set up selected_tune and selected_arch
+    as all the other target-specific codegen decisions are
+    derived from them.  */
+void
+riscv_override_options_internal (struct gcc_options *opts)
 {
   const struct riscv_tune_info *cpu;
 
-#ifdef SUBTARGET_OVERRIDE_OPTIONS
-  SUBTARGET_OVERRIDE_OPTIONS;
-#endif
-
-  flag_pcc_struct_return = 0;
-
-  if (flag_pic)
-    g_switch_value = 0;
-
   /* The presence of the M extension implies that division instructions
      are present, so include them unless explicitly disabled.  */
-  if (TARGET_MUL && (target_flags_explicit & MASK_DIV) == 0)
-    target_flags |= MASK_DIV;
-  else if (!TARGET_MUL && TARGET_DIV)
+  if (TARGET_MUL_OPTS_P (opts) && (target_flags_explicit & MASK_DIV) == 0)
+    opts->x_target_flags |= MASK_DIV;
+  else if (!TARGET_MUL_OPTS_P (opts) && TARGET_DIV_OPTS_P (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)
-    target_flags |= MASK_FDIV;
+    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 (riscv_tune_string ? riscv_tune_string :
-			  (riscv_cpu_string ? riscv_cpu_string :
+  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));
   riscv_microarchitecture = cpu->microarchitecture;
-  tune_param = 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,
@@ -8082,15 +8076,38 @@ riscv_option_override (void)
 
   if ((target_flags_explicit & MASK_STRICT_ALIGN) == 0
       && cpu->tune_param->slow_unaligned_access)
-    target_flags |= MASK_STRICT_ALIGN;
+    opts->x_target_flags |= MASK_STRICT_ALIGN;
 
   /* If the user hasn't specified a branch cost, use the processor's
      default.  */
-  if (riscv_branch_cost == 0)
-    riscv_branch_cost = tune_param->branch_cost;
+  if (opts->x_riscv_branch_cost == 0)
+    opts->x_riscv_branch_cost = tune_param->branch_cost;
 
-  /* Function to allocate machine-dependent function status.  */
-  init_machine_status = &riscv_init_machine_status;
+  /* FIXME: We don't allow TARGET_MIN_VLEN > 4096 since the datatypes of
+     both GET_MODE_SIZE and GET_MODE_BITSIZE are poly_uint16.
+
+     We can only allow TARGET_MIN_VLEN * 8 (LMUL) < 65535.  */
+  if (TARGET_MIN_VLEN_OPTS (opts) > 4096)
+    sorry ("Current RISC-V GCC cannot support VLEN greater than 4096bit for "
+	   "'V' Extension");
+
+  /* Convert -march to a chunks count.  */
+  riscv_vector_chunks = riscv_convert_vector_bits (opts);
+}
+
+/* Implement TARGET_OPTION_OVERRIDE.  */
+
+static void
+riscv_option_override (void)
+{
+#ifdef SUBTARGET_OVERRIDE_OPTIONS
+  SUBTARGET_OVERRIDE_OPTIONS;
+#endif
+
+  flag_pcc_struct_return = 0;
+
+  if (flag_pic)
+    g_switch_value = 0;
 
   if (flag_pic)
     riscv_cmodel = CM_PIC;
@@ -8205,20 +8222,14 @@ riscv_option_override (void)
       riscv_stack_protector_guard_offset = offs;
     }
 
-  /* FIXME: We don't allow TARGET_MIN_VLEN > 4096 since the datatypes of
-     both GET_MODE_SIZE and GET_MODE_BITSIZE are poly_uint16.
-
-     We can only allow TARGET_MIN_VLEN * 8 (LMUL) < 65535.  */
-  if (TARGET_MIN_VLEN > 4096)
-    sorry (
-      "Current RISC-V GCC cannot support VLEN greater than 4096bit for 'V' Extension");
-
   SET_OPTION_IF_UNSET (&global_options, &global_options_set,
 		       param_sched_pressure_algorithm,
 		       SCHED_PRESSURE_MODEL);
 
-  /* Convert -march to a chunks count.  */
-  riscv_vector_chunks = riscv_convert_vector_bits ();
+  /* Function to allocate machine-dependent function status.  */
+  init_machine_status = &riscv_init_machine_status;
+
+  riscv_override_options_internal (&global_options);
 }
 
 /* Implement TARGET_CONDITIONAL_REGISTER_USAGE.  */
-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v1 3/4] RISC-V: Extend riscv_subset_list, preparatory for target attribute support
  2023-10-03  9:09 Kito Cheng
  2023-10-03  9:09 ` [PATCH v1 1/4] options: Define TARGET_<NAME>_P and TARGET_<NAME>_OPTS_P macro for Mask and InverseMask Kito Cheng
  2023-10-03  9:09 ` [PATCH v1 2/4] RISC-V: Refactor riscv_option_override and riscv_convert_vector_bits. [NFC] Kito Cheng
@ 2023-10-03  9:09 ` Kito Cheng
  2023-10-03  9:09 ` [PATCH v1 4/4] RISC-V: Implement target attribute Kito Cheng
  2023-10-03  9:11 ` Kito Cheng
  4 siblings, 0 replies; 9+ messages in thread
From: Kito Cheng @ 2023-10-03  9:09 UTC (permalink / raw)
  To: gcc-patches, kito.cheng, palmer, jeffreyalaw, rdapp, juzhe.zhong
  Cc: Kito Cheng

riscv_subset_list only accept a full arch string before, but we need to
parse single extension when supporting target attribute, also we may set
a riscv_subset_list directly rather than re-parsing the ISA string
again.

gcc/ChangeLog:

	* config/riscv/riscv-subset.h (riscv_subset_list::parse_single_std_ext):
	New.
	(riscv_subset_list::parse_single_multiletter_ext): Ditto.
	(riscv_subset_list::clone): Ditto.
	(riscv_subset_list::parse_single_ext): Ditto.
	(riscv_subset_list::set_loc): Ditto.
	(riscv_set_arch_by_subset_list): Ditto.
	* common/config/riscv/riscv-common.cc
	(riscv_subset_list::parse_single_std_ext): New.
	(riscv_subset_list::parse_single_multiletter_ext): Ditto.
	(riscv_subset_list::clone): Ditto.
	(riscv_subset_list::parse_single_ext): Ditto.
	(riscv_subset_list::set_loc): Ditto.
	(riscv_set_arch_by_subset_list): Ditto.
---
 gcc/common/config/riscv/riscv-common.cc | 210 ++++++++++++++++++++++++
 gcc/config/riscv/riscv-subset.h         |  11 ++
 2 files changed, 221 insertions(+)

diff --git a/gcc/common/config/riscv/riscv-common.cc b/gcc/common/config/riscv/riscv-common.cc
index 9a0a68fe5db..76a1378874d 100644
--- a/gcc/common/config/riscv/riscv-common.cc
+++ b/gcc/common/config/riscv/riscv-common.cc
@@ -1036,6 +1036,41 @@ riscv_subset_list::parse_std_ext (const char *p)
   return p;
 }
 
+/* Parsing function for one standard extensions.
+
+   Return Value:
+     Points to the end of extensions.
+
+   Arguments:
+     `p`: Current parsing position.  */
+
+const char *
+riscv_subset_list::parse_single_std_ext (const char *p)
+{
+  if (*p == 'x' || *p == 's' || *p == 'z')
+    {
+      error_at (m_loc,
+		"%<-march=%s%>: Not single-letter extension. "
+		"%<%c%>",
+		m_arch, *p);
+      return nullptr;
+    }
+
+  unsigned major_version = 0;
+  unsigned minor_version = 0;
+  bool explicit_version_p = false;
+  char subset[2] = {0, 0};
+
+  subset[0] = *p;
+
+  p++;
+
+  p = parsing_subset_version (subset, p, &major_version, &minor_version,
+			      /* std_ext_p= */ true, &explicit_version_p);
+
+  add (subset, major_version, minor_version, explicit_version_p, false);
+  return p;
+}
 
 /* Check any implied extensions for EXT.  */
 void
@@ -1138,6 +1173,109 @@ riscv_subset_list::handle_combine_ext ()
     }
 }
 
+/* Parsing function for multi-letter extensions.
+
+   Return Value:
+     Points to the end of extensions.
+
+   Arguments:
+     `p`: Current parsing position.
+     `ext_type`: What kind of extensions, 's', 'z' or 'x'.
+     `ext_type_str`: Full name for kind of extension.  */
+
+
+const char *
+riscv_subset_list::parse_single_multiletter_ext (const char *p,
+						 const char *ext_type,
+						 const char *ext_type_str)
+{
+  unsigned major_version = 0;
+  unsigned minor_version = 0;
+  size_t ext_type_len = strlen (ext_type);
+
+    {
+      if (strncmp (p, ext_type, ext_type_len) != 0)
+	return NULL;
+
+      char *subset = xstrdup (p);
+      char *q = subset;
+      const char *end_of_version;
+      bool explicit_version_p = false;
+      char *ext;
+      char backup;
+      size_t len;
+      size_t end_of_version_pos, i;
+      bool found_any_number = false;
+      bool found_minor_version = false;
+
+      backup = *q;
+      *q = '\0';
+      len = q - subset;
+      *q = backup;
+
+      end_of_version_pos = len;
+      /* Find the begin of version string.  */
+      for (i = len -1; i > 0; --i)
+	{
+	  if (ISDIGIT (subset[i]))
+	    {
+	      found_any_number = true;
+	      continue;
+	    }
+	  /* Might be version seperator, but need to check one more char,
+	     we only allow <major>p<minor>, so we could stop parsing if found
+	     any more `p`.  */
+	  if (subset[i] == 'p' &&
+	      !found_minor_version &&
+	      found_any_number && ISDIGIT (subset[i-1]))
+	    {
+	      found_minor_version = true;
+	      continue;
+	    }
+
+	  end_of_version_pos = i + 1;
+	  break;
+	}
+
+      backup = subset[end_of_version_pos];
+      subset[end_of_version_pos] = '\0';
+      ext = xstrdup (subset);
+      subset[end_of_version_pos] = backup;
+
+      end_of_version
+	= parsing_subset_version (ext, subset + end_of_version_pos, &major_version, &minor_version,
+				  /* std_ext_p= */ false, &explicit_version_p);
+      free (ext);
+
+      if (end_of_version == NULL)
+	return NULL;
+
+      subset[end_of_version_pos] = '\0';
+
+      if (strlen (subset) == 1)
+	{
+	  error_at (m_loc, "%<-march=%s%>: name of %s must be more than 1 letter",
+		    m_arch, ext_type_str);
+	  free (subset);
+	  return NULL;
+	}
+
+      add (subset, major_version, minor_version, explicit_version_p, false);
+      p += end_of_version - subset;
+      free (subset);
+
+      if (*p != '\0' && *p != '_')
+	{
+	  error_at (m_loc, "%<-march=%s%>: %s must separate with %<_%>",
+		    m_arch, ext_type_str);
+	  return NULL;
+	}
+    }
+
+  return p;
+
+}
+
 /* Parsing function for multi-letter extensions.
 
    Return Value:
@@ -1250,6 +1388,30 @@ riscv_subset_list::parse_multiletter_ext (const char *p,
   return p;
 }
 
+/* Parsing function for a single-letter or multi-letter extensions.
+
+   Return Value:
+     Points to the end of extensions.
+
+   Arguments:
+     `p`: Current parsing position.  */
+
+const char *
+riscv_subset_list::parse_single_ext (const char *p)
+{
+  switch (p[0])
+    {
+    case 'x':
+      return parse_single_multiletter_ext (p, "x", "non-standard extension");
+    case 'z':
+      return parse_single_multiletter_ext (p, "z", "sub-extension");
+    case 's':
+      return parse_single_multiletter_ext (p, "s", "supervisor extension");
+    default:
+      return parse_single_std_ext (p);
+    }
+}
+
 /* Parsing arch string to subset list, return NULL if parsing failed.  */
 
 riscv_subset_list *
@@ -1342,6 +1504,26 @@ fail:
   return NULL;
 }
 
+/* Clone whole subset list.  */
+
+riscv_subset_list *
+riscv_subset_list::clone () const
+{
+  riscv_subset_list *new_list = new riscv_subset_list (m_arch, m_loc);
+  for (riscv_subset_t *itr = m_head; itr != NULL; itr = itr->next)
+    new_list->add (itr->name.c_str (), itr->major_version, itr->minor_version,
+		   itr->explicit_version_p, true);
+
+  new_list->m_xlen = m_xlen;
+  return new_list;
+}
+
+void
+riscv_subset_list::set_loc (location_t loc)
+{
+  m_loc = loc;
+}
+
 /* Return the current arch string.  */
 
 std::string
@@ -1498,6 +1680,34 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] =
   {NULL, NULL, 0}
 };
 
+void
+riscv_set_arch_by_subset_list (riscv_subset_list *subset_list,
+			       struct gcc_options *opts)
+{
+  if (opts)
+    {
+      const riscv_ext_flag_table_t *arch_ext_flag_tab;
+      /* Clean up target flags before we set.  */
+      for (arch_ext_flag_tab = &riscv_ext_flag_table[0]; arch_ext_flag_tab->ext;
+	   ++arch_ext_flag_tab)
+	opts->*arch_ext_flag_tab->var_ref &= ~arch_ext_flag_tab->mask;
+
+      if (subset_list->xlen () == 32)
+	opts->x_target_flags &= ~MASK_64BIT;
+      else if (subset_list->xlen () == 64)
+	opts->x_target_flags |= MASK_64BIT;
+
+      for (arch_ext_flag_tab = &riscv_ext_flag_table[0]; arch_ext_flag_tab->ext;
+	   ++arch_ext_flag_tab)
+	{
+	  if (subset_list->lookup (arch_ext_flag_tab->ext))
+	    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
    dependent mask bits, in case more than one -march string is passed.  */
 
diff --git a/gcc/config/riscv/riscv-subset.h b/gcc/config/riscv/riscv-subset.h
index dca07284efa..d2a4bd20530 100644
--- a/gcc/config/riscv/riscv-subset.h
+++ b/gcc/config/riscv/riscv-subset.h
@@ -69,8 +69,12 @@ private:
 
   const char *parse_std_ext (const char *);
 
+  const char *parse_single_std_ext (const char *);
+
   const char *parse_multiletter_ext (const char *, const char *,
 				     const char *);
+  const char *parse_single_multiletter_ext (const char *, const char *,
+					    const char *);
 
   void handle_implied_ext (const char *);
   bool check_implied_ext ();
@@ -91,14 +95,21 @@ public:
 
   unsigned xlen () const {return m_xlen;};
 
+  riscv_subset_list *clone () const;
+
   static riscv_subset_list *parse (const char *, location_t);
+  const char *parse_single_ext (const char *);
 
   const riscv_subset_t *begin () const {return m_head;};
   const riscv_subset_t *end () const {return NULL;};
 
   int match_score (riscv_subset_list *) const;
+
+  void set_loc (location_t);
 };
 
 extern const riscv_subset_list *riscv_current_subset_list (void);
+extern void
+riscv_set_arch_by_subset_list (riscv_subset_list *, struct gcc_options *);
 
 #endif /* ! GCC_RISCV_SUBSET_H */
-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v1 4/4] RISC-V: Implement target attribute
  2023-10-03  9:09 Kito Cheng
                   ` (2 preceding siblings ...)
  2023-10-03  9:09 ` [PATCH v1 3/4] RISC-V: Extend riscv_subset_list, preparatory for target attribute support Kito Cheng
@ 2023-10-03  9:09 ` Kito Cheng
  2023-10-03  9:11 ` Kito Cheng
  4 siblings, 0 replies; 9+ messages in thread
From: Kito Cheng @ 2023-10-03  9:09 UTC (permalink / raw)
  To: gcc-patches, kito.cheng, palmer, jeffreyalaw, rdapp, juzhe.zhong
  Cc: Kito Cheng

The target attribute which proposed in [1], target attribute allow user
to specify a local setting per-function basis.

The syntax of target attribute is `__attribute__((target("<ATTR-STRING>")))`.

and the syntax of `<ATTR-STRING>` describes below:
```
ATTR-STRING := ATTR-STRING ';' ATTR
             | ATTR

ATTR        := ARCH-ATTR
             | CPU-ATTR
             | TUNE-ATTR

ARCH-ATTR   := 'arch=' EXTENSIONS-OR-FULLARCH

EXTENSIONS-OR-FULLARCH := <EXTENSIONS>
                        | <FULLARCHSTR>

EXTENSIONS             := <EXTENSION> ',' <EXTENSIONS>
                        | <EXTENSION>

FULLARCHSTR            := <full-arch-string>

EXTENSION              := <OP> <EXTENSION-NAME> <VERSION>

OP                     := '+'

VERSION                := [0-9]+ 'p' [0-9]+
                        | [1-9][0-9]*
                        |

EXTENSION-NAME         := Naming rule is defined in RISC-V ISA manual

CPU-ATTR    := 'cpu=' <valid-cpu-name>
TUNE-ATTR   := 'tune=' <valid-tune-name>
```

[1] https://github.com/riscv-non-isa/riscv-c-api-doc/pull/35

gcc/ChangeLog:

	* config.gcc (riscv): Add riscv-target-attr.o.
	* config/riscv/riscv-opts.h (TARGET_MIN_VLEN_OPTS): New.
	* config/riscv/riscv-protos.h (riscv_declare_function_size) New.
	(riscv_option_valid_attribute_p): New.
	(riscv_override_options_internal): New.
	(struct riscv_tune_info): New.
	(riscv_parse_tune): New.
	* config/riscv/riscv-target-attr.cc
	(class riscv_target_attr_parser): New.
	(struct riscv_attribute_info): New.
	(riscv_attributes): New.
	(riscv_target_attr_parser::parse_arch):
	(riscv_target_attr_parser::handle_arch):
	(riscv_target_attr_parser::handle_cpu):
	(riscv_target_attr_parser::handle_tune):
	(riscv_target_attr_parser::update_settings):
	(riscv_process_one_target_attr):
	(num_occurences_in_str):
	(riscv_process_target_attr):
	(riscv_option_valid_attribute_p):
	* config/riscv/riscv.cc: Include target-globals.h and
	riscv-subset.h.
	(struct riscv_tune_info): Move to riscv-protos.h.
	(get_tune_str):
	(riscv_parse_tune):
	(riscv_declare_function_size):
	(riscv_option_override): Build target_option_default_node and
	target_option_current_node.
	(riscv_save_restore_target_globals):
	(riscv_option_restore):
	(riscv_previous_fndecl):
	(riscv_set_current_function): Apply the target attribute.
	(TARGET_OPTION_RESTORE): Define.
	(TARGET_OPTION_VALID_ATTRIBUTE_P): Ditto.
	* config/riscv/riscv.h (SWITCHABLE_TARGET): Define to 1.
	(ASM_DECLARE_FUNCTION_SIZE) Define.
	* config/riscv/riscv.opt (mtune=): Add Save attribute.
	(mcpu=): Ditto.
	(mcmodel=): Ditto.
	* config/riscv/t-riscv: Add build rule for riscv-target-attr.o
	* doc/extend.texi: Add doc for target attribute.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/target-attr-01.c: New.
	* gcc.target/riscv/target-attr-02.c: Ditto.
	* gcc.target/riscv/target-attr-03.c: Ditto.
	* gcc.target/riscv/target-attr-04.c: Ditto.
	* gcc.target/riscv/target-attr-05.c: Ditto.
	* gcc.target/riscv/target-attr-06.c: Ditto.
	* gcc.target/riscv/target-attr-07.c: Ditto.
	* gcc.target/riscv/target-attr-bad-01.c: Ditto.
	* gcc.target/riscv/target-attr-bad-02.c: Ditto.
	* gcc.target/riscv/target-attr-bad-03.c: Ditto.
	* gcc.target/riscv/target-attr-bad-04.c: Ditto.
	* gcc.target/riscv/target-attr-bad-05.c: Ditto.
	* gcc.target/riscv/target-attr-bad-06.c: Ditto.
	* gcc.target/riscv/target-attr-bad-07.c: Ditto.
	* gcc.target/riscv/target-attr-warning-01.c: Ditto.
	* gcc.target/riscv/target-attr-warning-02.c: Ditto.
	* gcc.target/riscv/target-attr-warning-03.c: Ditto.
---
 gcc/config.gcc                                |   2 +-
 gcc/config/riscv/riscv-opts.h                 |   6 +
 gcc/config/riscv/riscv-protos.h               |  21 +
 gcc/config/riscv/riscv-target-attr.cc         | 396 ++++++++++++++++++
 gcc/config/riscv/riscv.cc                     | 192 +++++++--
 gcc/config/riscv/riscv.h                      |   6 +
 gcc/config/riscv/riscv.opt                    |   6 +-
 gcc/config/riscv/t-riscv                      |   5 +
 gcc/doc/extend.texi                           |  58 +++
 .../gcc.target/riscv/target-attr-01.c         |  31 ++
 .../gcc.target/riscv/target-attr-02.c         |  31 ++
 .../gcc.target/riscv/target-attr-03.c         |  26 ++
 .../gcc.target/riscv/target-attr-04.c         |  28 ++
 .../gcc.target/riscv/target-attr-05.c         |  27 ++
 .../gcc.target/riscv/target-attr-06.c         |  27 ++
 .../gcc.target/riscv/target-attr-07.c         |  25 ++
 .../gcc.target/riscv/target-attr-bad-01.c     |  13 +
 .../gcc.target/riscv/target-attr-bad-02.c     |  13 +
 .../gcc.target/riscv/target-attr-bad-03.c     |  13 +
 .../gcc.target/riscv/target-attr-bad-04.c     |  13 +
 .../gcc.target/riscv/target-attr-bad-05.c     |  13 +
 .../gcc.target/riscv/target-attr-bad-06.c     |  13 +
 .../gcc.target/riscv/target-attr-bad-07.c     |  13 +
 .../gcc.target/riscv/target-attr-warning-01.c |   8 +
 .../gcc.target/riscv/target-attr-warning-02.c |   8 +
 .../gcc.target/riscv/target-attr-warning-03.c |   8 +
 26 files changed, 957 insertions(+), 45 deletions(-)
 create mode 100644 gcc/config/riscv/riscv-target-attr.cc
 create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-01.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-02.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-03.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-04.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-05.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-06.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-07.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-01.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-02.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-03.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-04.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-05.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-06.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-bad-07.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-warning-01.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-warning-02.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/target-attr-warning-03.c

diff --git a/gcc/config.gcc b/gcc/config.gcc
index ee46d96bf62..b62fb096b59 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -544,7 +544,7 @@ riscv*)
 	extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o riscv-selftests.o riscv-string.o"
 	extra_objs="${extra_objs} riscv-v.o riscv-vsetvl.o riscv-vector-costs.o"
 	extra_objs="${extra_objs} riscv-vector-builtins.o riscv-vector-builtins-shapes.o riscv-vector-builtins-bases.o"
-	extra_objs="${extra_objs} thead.o"
+	extra_objs="${extra_objs} thead.o riscv-target-attr.o"
 	d_target_objs="riscv-d.o"
 	extra_headers="riscv_vector.h"
 	target_gtfiles="$target_gtfiles \$(srcdir)/config/riscv/riscv-vector-builtins.cc"
diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h
index 7e4b0cc6fe1..8d0ae3237c3 100644
--- a/gcc/config/riscv/riscv-opts.h
+++ b/gcc/config/riscv/riscv-opts.h
@@ -111,6 +111,12 @@ enum riscv_entity
    ? 0 \
    : 32 << (__builtin_popcount (riscv_zvl_flags) - 1))
 
+/* Same as TARGET_MIN_VLEN, but take an OPTS as gcc_options.  */
+#define TARGET_MIN_VLEN_OPTS(opts)                                             \
+  ((opts->x_riscv_zvl_flags == 0)                                              \
+     ? 0                                                                       \
+     : 32 << (__builtin_popcount (opts->x_riscv_zvl_flags) - 1))
+
 /* We only enable VLS modes for VLA vectorization since fixed length VLMAX mode
    is the highest priority choice and should not conflict with VLS modes.  */
 #define TARGET_VECTOR_VLS                                                      \
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index af5baf37e6a..c3107be1391 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -103,6 +103,7 @@ extern void riscv_split_doubleword_move (rtx, rtx);
 extern const char *riscv_output_move (rtx, rtx);
 extern const char *riscv_output_return ();
 extern void riscv_declare_function_name (FILE *, const char *, tree);
+extern void riscv_declare_function_size (FILE *, const char *, tree);
 extern void riscv_asm_output_alias (FILE *, const tree, const tree);
 extern void riscv_asm_output_external (FILE *, const tree, const char *);
 extern bool
@@ -578,5 +579,25 @@ th_mempair_output_move (rtx[4], bool, machine_mode, RTX_CODE);
 
 extern bool riscv_use_divmod_expander (void);
 void riscv_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int);
+extern bool
+riscv_option_valid_attribute_p (tree, tree, tree, int);
+extern void
+riscv_override_options_internal (struct gcc_options *);
+
+struct riscv_tune_param;
+/* Information about one micro-arch we know about.  */
+struct riscv_tune_info {
+  /* This micro-arch canonical name.  */
+  const char *name;
+
+  /* Which automaton to use for tuning.  */
+  enum riscv_microarchitecture_type microarchitecture;
+
+  /* Tuning parameters for this micro-arch.  */
+  const struct riscv_tune_param *tune_param;
+};
+
+const struct riscv_tune_info *
+riscv_parse_tune (const char *, bool);
 
 #endif /* ! GCC_RISCV_PROTOS_H */
diff --git a/gcc/config/riscv/riscv-target-attr.cc b/gcc/config/riscv/riscv-target-attr.cc
new file mode 100644
index 00000000000..9eec3b951c7
--- /dev/null
+++ b/gcc/config/riscv/riscv-target-attr.cc
@@ -0,0 +1,396 @@
+/* Subroutines used for parsing target attribute for RISC-V.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#define IN_TARGET_CODE 1
+
+#define INCLUDE_STRING
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "target.h"
+#include "tree.h"
+#include "tm_p.h"
+#include "diagnostic.h"
+#include "opts.h"
+#include "riscv-subset.h"
+
+namespace {
+class riscv_target_attr_parser
+{
+public:
+  riscv_target_attr_parser (location_t loc)
+    : m_found_arch_p (false)
+    , m_found_tune_p (false)
+    , m_found_cpu_p (false)
+    , m_subset_list (nullptr)
+    , m_loc (loc)
+    , m_cpu_info (nullptr)
+    , m_tune (nullptr)
+  {
+  }
+
+  bool handle_arch (const char *);
+  bool handle_cpu (const char *);
+  bool handle_tune (const char *);
+
+  void set_loc (location_t loc) {
+    m_loc = loc;
+  }
+
+  void update_settings (struct gcc_options *opts) const;
+private:
+  const char *m_raw_attr_str;
+  bool parse_arch (const char *);
+
+  bool m_found_arch_p;
+  bool m_found_tune_p;
+  bool m_found_cpu_p;
+  riscv_subset_list *m_subset_list;
+  location_t m_loc;
+  const  riscv_cpu_info *m_cpu_info;
+  const char *m_tune;
+};
+}
+
+/* All the information needed to handle a target attribute.
+   NAME is the name of the attribute.
+   HANDLER is the function that takes the attribute string as an argument.  */
+
+struct riscv_attribute_info
+{
+  const char *name;
+  bool (riscv_target_attr_parser::*handler) (const char *);
+};
+
+/* The target attributes that we support.  */
+
+static const struct riscv_attribute_info riscv_attributes[]
+  = {{"arch", &riscv_target_attr_parser::handle_arch},
+     {"cpu", &riscv_target_attr_parser::handle_cpu},
+     {"tune", &riscv_target_attr_parser::handle_tune}};
+
+bool
+riscv_target_attr_parser::parse_arch (const char *str)
+{
+  if (m_subset_list)
+    delete m_subset_list;
+  /* Check if it's setting full arch string.  */
+  if (strncmp ("rv", str, strlen ("rv")) == 0)
+    {
+      m_subset_list = riscv_subset_list::parse (str, location_t ());
+
+      if (m_subset_list == nullptr)
+	goto fail;
+
+      return true;
+    }
+  else
+    {
+      /* Parsing the extension list like "+<ext>[,+<ext>]*".  */
+      size_t len = strlen (str);
+      char *str_to_check = (char *) alloca (len + 1);
+      strcpy (str_to_check, str);
+      const char *token = strtok_r (str_to_check, ",", &str_to_check);
+      m_subset_list = riscv_current_subset_list ()->clone ();
+      m_subset_list->set_loc (m_loc);
+      while (token)
+	{
+	  if (token[0] != '+')
+	    {
+	      error_at (
+		m_loc,
+		"unexpected arch for %<target()%> attribute: must start "
+		"with + or rv");
+	      goto fail;
+	    }
+	  else
+	    {
+	      const char *result = m_subset_list->parse_single_ext (token + 1);
+	      /* Check parse_single_ext has consume all string.  */
+	      if (*result != '\0')
+		{
+		  error_at (
+		    m_loc,
+		    "unexpected arch for %<target()%> attribute: bad "
+		    "string found %<%s%>", token);
+		  goto fail;
+		}
+	    }
+	  token = strtok_r (NULL, ",", &str_to_check);
+	}
+
+      return true;
+    }
+fail:
+  if (m_subset_list != nullptr)
+    {
+      delete m_subset_list;
+      m_subset_list = nullptr;
+    }
+  return false;
+}
+
+/* Handle the ARCH_STR argument to the arch= target attribute.  */
+
+bool
+riscv_target_attr_parser::handle_arch (const char *str)
+{
+  if (m_found_arch_p)
+    warning_at (m_loc, 0,
+		"%<target()%> attribute: arch appears more than once, the "
+		"settings of the last one will be used");
+  m_found_arch_p = true;
+  return parse_arch (str);
+}
+
+/* Handle the CPU_STR argument to the cpu= target attribute.  */
+
+bool
+riscv_target_attr_parser::handle_cpu (const char *str)
+{
+  if (m_found_cpu_p)
+    warning_at (m_loc, 0,
+		"%<target()%> attribute: cpu appears more than once, the "
+		"settings of the last one will be used");
+
+  m_found_cpu_p = true;
+  const riscv_cpu_info *cpu_info = riscv_find_cpu (str);
+
+  if (!cpu_info)
+    {
+      error_at (m_loc, 0, "%<target()%> attribute: unknown CPU %<%s%>", str);
+      return false;
+    }
+
+  if (m_subset_list == nullptr)
+    {
+      const char *arch_str = cpu_info->arch;
+      m_subset_list = riscv_subset_list::parse (arch_str, m_loc);
+      gcc_assert (m_subset_list);
+    }
+
+  m_cpu_info = cpu_info;
+  return true;
+}
+
+/* Handle the TUNE_STR argument to the tune= target attribute.  */
+
+bool
+riscv_target_attr_parser::handle_tune (const char *str)
+{
+  if (m_found_tune_p)
+    warning_at (m_loc, 0,
+		"%<target()%> attribute: tune appears more than once, the "
+		"settings of the last one will be used");
+  m_found_tune_p = true;
+  const struct riscv_tune_info *tune = riscv_parse_tune (str, true);
+
+  if (tune == nullptr)
+    {
+      error_at (m_loc, 0, "%<target()%> attribute: unknown TUNE %<%s%>", str);
+      return false;
+    }
+
+  m_tune = tune->name;
+
+  return true;
+}
+
+void
+riscv_target_attr_parser::update_settings (struct gcc_options *opts) const
+{
+  if (m_subset_list)
+    riscv_set_arch_by_subset_list (m_subset_list, opts);
+
+  if (m_cpu_info)
+    opts->x_riscv_cpu_string = m_cpu_info->name;
+
+  if (m_tune)
+    opts->x_riscv_tune_string = m_tune;
+  else
+    {
+      if (m_cpu_info)
+	opts->x_riscv_tune_string = m_cpu_info->tune;
+    }
+}
+
+/* Parse ARG_STR which contains the definition of one target attribute.
+   Show appropriate errors if any or return true if the attribute is valid.  */
+
+static bool
+riscv_process_one_target_attr (char *arg_str,
+			       location_t loc,
+			       riscv_target_attr_parser &attr_parser)
+{
+  size_t len = strlen (arg_str);
+
+  if (len == 0)
+    {
+      error_at (loc, "malformed %<target()%> attribute");
+      return false;
+    }
+
+  char *str_to_check = (char *) alloca (len + 1);
+  strcpy (str_to_check, arg_str);
+
+  char *arg = strchr (str_to_check, '=');
+
+  if (!arg)
+    {
+      error_at (
+	loc,
+	"attribute %<target(\"%s\")%> does not accept an argument",
+	str_to_check);
+      return false;
+    }
+
+  arg[0] = '\0';
+  ++arg;
+  for (const auto &attr : riscv_attributes)
+    {
+      /* If the names don't match up, or the user has given an argument
+	 to an attribute that doesn't accept one, or didn't give an argument
+	 to an attribute that expects one, fail to match.  */
+      if (strncmp (str_to_check, attr.name, strlen (attr.name)) != 0)
+	continue;
+
+      return (&attr_parser->*attr.handler) (arg);
+    }
+  error_at (loc, "Got unknown attribute %<target(\"%s\")%>", str_to_check);
+
+  return false;
+}
+
+/* Count how many times the character C appears in
+   NULL-terminated string STR.  */
+
+static unsigned int
+num_occurences_in_str (char c, char *str)
+{
+  unsigned int res = 0;
+  while (*str != '\0')
+    {
+      if (*str == c)
+	res++;
+
+      str++;
+    }
+
+  return res;
+}
+
+/* Parse the tree in ARGS that contains the target attribute information
+   and update the global target options space.  */
+
+static bool
+riscv_process_target_attr (tree args, location_t loc, struct gcc_options *opts)
+{
+  if (TREE_CODE (args) == TREE_LIST)
+    {
+      do
+	{
+	  tree head = TREE_VALUE (args);
+	  if (head)
+	    {
+	      if (!riscv_process_target_attr (head, loc, opts))
+		return false;
+	    }
+	  args = TREE_CHAIN (args);
+      } while (args);
+
+      return true;
+    }
+
+  if (TREE_CODE (args) != STRING_CST)
+    {
+      error_at (loc, "attribute %<target%> argument not a string");
+      return false;
+    }
+  size_t len = strlen (TREE_STRING_POINTER (args));
+  char *str_to_check = (char *) alloca (len + 1);
+  strcpy (str_to_check, TREE_STRING_POINTER (args));
+
+  if (len == 0)
+    {
+      error_at (loc, "malformed %<target()%> attribute");
+      return false;
+    }
+
+  /* Used to catch empty spaces between commas i.e.
+     attribute ((target ("attr1;;attr2"))).  */
+  unsigned int num_commas = num_occurences_in_str (';', str_to_check);
+
+  /* Handle multiple target attributes separated by ','.  */
+  char *token = strtok_r (str_to_check, ";", &str_to_check);
+
+  riscv_target_attr_parser attr_parser (loc);
+  unsigned int num_attrs = 0;
+  while (token)
+    {
+      num_attrs++;
+      riscv_process_one_target_attr (token, loc, attr_parser);
+      token = strtok_r (NULL, ";", &str_to_check);
+    }
+
+  if (num_attrs != num_commas + 1)
+    {
+      error_at (loc, "malformed %<target(\"%s\")%> attribute",
+		TREE_STRING_POINTER (args));
+      return false;
+    }
+
+  /* Apply settings from target attribute.  */
+  attr_parser.update_settings (opts);
+
+  return true;
+}
+
+/* Implement TARGET_OPTION_VALID_ATTRIBUTE_P.  This is used to
+   process attribute ((target ("..."))).  */
+
+bool
+riscv_option_valid_attribute_p (tree fndecl, tree, tree args, int)
+{
+  struct cl_target_option cur_target;
+  bool ret;
+  tree new_target;
+  location_t loc = DECL_SOURCE_LOCATION (fndecl);
+
+  /* Save the current target options to restore at the end.  */
+  cl_target_option_save (&cur_target, &global_options, &global_options_set);
+
+  ret = riscv_process_target_attr (args, loc, &global_options);
+
+  if (ret)
+    {
+      riscv_override_options_internal (&global_options);
+      new_target
+	= build_target_option_node (&global_options, &global_options_set);
+    }
+  else
+    new_target = NULL;
+
+  if (fndecl && ret)
+    {
+      DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = new_target;
+    }
+
+  cl_target_option_restore (&global_options, &global_options_set, &cur_target);
+  return ret;
+}
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index d089ec1b241..ace2903a13d 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -73,10 +73,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-vectorizer.h"
 #include "gcse.h"
 #include "tree-dfa.h"
+#include "target-globals.h"
 
 /* This file should be included last.  */
 #include "target-def.h"
 #include "riscv-vector-costs.h"
+#include "riscv-subset.h"
 
 /* True if X is an UNSPEC wrapper around a SYMBOL_REF or LABEL_REF.  */
 #define UNSPEC_ADDRESS_P(X)					\
@@ -261,17 +263,6 @@ struct riscv_tune_param
   bool use_divmod_expansion;
 };
 
-/* Information about one micro-arch we know about.  */
-struct riscv_tune_info {
-  /* This micro-arch canonical name.  */
-  const char *name;
-
-  /* Which automaton to use for tuning.  */
-  enum riscv_microarchitecture_type microarchitecture;
-
-  /* Tuning parameters for this micro-arch.  */
-  const struct riscv_tune_param *tune_param;
-};
 
 /* Global variables for machine-dependent things.  */
 
@@ -483,10 +474,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);
 
@@ -497,6 +501,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;
 }
@@ -7845,6 +7852,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.  */
@@ -8051,16 +8085,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,
@@ -8072,7 +8108,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)
@@ -8230,8 +8266,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
@@ -8477,7 +8546,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)
@@ -8485,36 +8559,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. */
@@ -9633,6 +9737,12 @@ riscv_preferred_else_value (unsigned ifn, tree vectype, unsigned int nops,
 #undef TARGET_OPTION_OVERRIDE
 #define TARGET_OPTION_OVERRIDE riscv_option_override
 
+#undef TARGET_OPTION_RESTORE
+#define TARGET_OPTION_RESTORE riscv_option_restore
+
+#undef TARGET_OPTION_VALID_ATTRIBUTE_P
+#define TARGET_OPTION_VALID_ATTRIBUTE_P riscv_option_valid_attribute_p
+
 #undef TARGET_LEGITIMIZE_ADDRESS
 #define TARGET_LEGITIMIZE_ADDRESS riscv_legitimize_address
 
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index 7ac78847b3a..a88c6f917a6 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -25,6 +25,8 @@ along with GCC; see the file COPYING3.  If not see
 #include <stdbool.h>
 #include "config/riscv/riscv-opts.h"
 
+#define SWITCHABLE_TARGET 1
+
 /* Target CPU builtins.  */
 #define TARGET_CPU_CPP_BUILTINS() riscv_cpu_cpp_builtins (pfile)
 
@@ -1054,6 +1056,10 @@ while (0)
 #define ASM_DECLARE_FUNCTION_NAME(STR, NAME, DECL)                             \
   riscv_declare_function_name (STR, NAME, DECL)
 
+#undef ASM_DECLARE_FUNCTION_SIZE
+#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL)                           \
+  riscv_declare_function_size (FILE, FNAME, DECL)
+
 /* Add output .variant_cc directive for specific alias definition.  */
 #undef ASM_OUTPUT_DEF_FROM_DECLS
 #define ASM_OUTPUT_DEF_FROM_DECLS(STR, DECL, TARGET)                           \
diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
index 9424b239058..17f3adcc622 100644
--- a/gcc/config/riscv/riscv.opt
+++ b/gcc/config/riscv/riscv.opt
@@ -84,11 +84,11 @@ Target RejectNegative Joined Negative(march=)
 lower-case.
 
 mtune=
-Target RejectNegative Joined Var(riscv_tune_string)
+Target RejectNegative Joined Var(riscv_tune_string) Save
 -mtune=PROCESSOR	Optimize the output for PROCESSOR.
 
 mcpu=
-Target RejectNegative Joined Var(riscv_cpu_string)
+Target RejectNegative Joined Var(riscv_cpu_string) Save
 -mcpu=PROCESSOR	Use architecture of and optimize the output for PROCESSOR.
 
 msmall-data-limit=
@@ -106,7 +106,7 @@ memory accesses to be generated as compressed instructions.  Currently targets
 32-bit integer load/stores.
 
 mcmodel=
-Target RejectNegative Joined Enum(code_model) Var(riscv_cmodel) Init(TARGET_DEFAULT_CMODEL)
+Target RejectNegative Joined Enum(code_model) Var(riscv_cmodel) Init(TARGET_DEFAULT_CMODEL) Save
 Specify the code model.
 
 mstrict-align
diff --git a/gcc/config/riscv/t-riscv b/gcc/config/riscv/t-riscv
index f137e1f17ef..d46459ff462 100644
--- a/gcc/config/riscv/t-riscv
+++ b/gcc/config/riscv/t-riscv
@@ -108,6 +108,11 @@ riscv-v.o: $(srcdir)/config/riscv/riscv-v.cc \
 	$(COMPILE) $<
 	$(POSTCOMPILE)
 
+riscv-target-attr.o: $(srcdir)/config/riscv/riscv-target-attr.cc $(CONFIG_H) \
+  $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(DIAGNOSTIC_CORE_H)
+	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+		$(srcdir)/config/riscv/riscv-target-attr.cc
+
 thead.o: $(srcdir)/config/riscv/thead.cc \
   $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TARGET_H) backend.h $(RTL_H) \
   memmodel.h $(EMIT_RTL_H) poly-int.h output.h
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index b4770f1a149..e8b0a823b59 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -6224,8 +6224,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..599d0a73ac0
--- /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-error "empty string in attribute" } */
+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..7bd7446e9eb
--- /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..ca54baf6aad
--- /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 "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-warning-01.c b/gcc/testsuite/gcc.target/riscv/target-attr-warning-01.c
new file mode 100644
index 00000000000..d4b6e4e505a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/target-attr-warning-01.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
+/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
+
+long foo() __attribute__((target("arch=rv64gc_zba;arch=rv64gc_zba"))); /* { dg-warning "arch appears more than once" } */
+long foo(long a, long b){
+  return a + (b * 2);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-warning-02.c b/gcc/testsuite/gcc.target/riscv/target-attr-warning-02.c
new file mode 100644
index 00000000000..b43b131c955
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/target-attr-warning-02.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
+/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
+
+long foo() __attribute__((target("cpu=sifive-u74;cpu=sifive-u74"))); /* { dg-warning "cpu appears more than once" } */
+long foo(long a, long b){
+  return a + (b * 2);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/target-attr-warning-03.c b/gcc/testsuite/gcc.target/riscv/target-attr-warning-03.c
new file mode 100644
index 00000000000..551c56e37dc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/target-attr-warning-03.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
+/* { dg-options "-march=rv64gc -O2 -mabi=lp64" } */
+
+long foo() __attribute__((target("tune=sifive-u74;tune=sifive-u74"))); /* { dg-warning "tune appears more than once" } */
+long foo(long a, long b){
+  return a + (b * 2);
+}
-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re:
  2023-10-03  9:09 Kito Cheng
                   ` (3 preceding siblings ...)
  2023-10-03  9:09 ` [PATCH v1 4/4] RISC-V: Implement target attribute Kito Cheng
@ 2023-10-03  9:11 ` Kito Cheng
  4 siblings, 0 replies; 9+ messages in thread
From: Kito Cheng @ 2023-10-03  9:11 UTC (permalink / raw)
  To: Kito Cheng; +Cc: gcc-patches, palmer, jeffreyalaw, rdapp, juzhe.zhong

Ooop, I screwed up when writing my cover letter of the target
attribute patch set...

On Tue, Oct 3, 2023 at 5:10 PM Kito Cheng <kito.cheng@sifive.com> wrote:
>
> From: Kito Cheng <kito.cheng@sifive.com>
>
> Reply-To:
>
> Subject: [PATCH v1 0/4] RISC-V target attribute
>
> In-Reply-To:
>
> This patch set implement target attribute for RISC-V target, which is similar to other target like x86 or ARM, let user able to set some local setting per function without changing global settings.
>
> We support arch, tune and cpu first, and we will support other target attribute later, this version DOES NOT include multi-version function support yet, that is future work, probably work for GCC 15.
>
> The full proposal is put in RISC-V C-API document[1], which has discussed with RISC-V LLVM community, so we have consistent syntax and semantics.
>
> [1] https://github.com/riscv-non-isa/riscv-c-api-doc/pull/35
>
>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v1 1/4] options: Define TARGET_<NAME>_P and TARGET_<NAME>_OPTS_P macro for Mask and InverseMask
  2023-10-03  9:09 ` [PATCH v1 1/4] options: Define TARGET_<NAME>_P and TARGET_<NAME>_OPTS_P macro for Mask and InverseMask Kito Cheng
@ 2023-10-09 14:16   ` Jeff Law
  2023-10-09 20:03     ` Kito Cheng
  0 siblings, 1 reply; 9+ messages in thread
From: Jeff Law @ 2023-10-09 14:16 UTC (permalink / raw)
  To: Kito Cheng, gcc-patches, kito.cheng, palmer, rdapp, juzhe.zhong



On 10/3/23 03:09, Kito Cheng wrote:
> We TARGET_<NAME>_P marcro to test a Mask and InverseMask with user
> specified target_variable, however we may want to test with specific
> gcc_options variable rather than target_variable.
> 
> Like RISC-V has defined lots of Mask with TargetVariable, which is not
> easy to use, because that means we need to known which Mask are associate with
> which TargetVariable, so take a gcc_options variable is a better interface
> for such use case.
> 
> gcc/ChangeLog:
> 
> 	* doc/options.texi (Mask): Document TARGET_<NAME>_P and
> 	TARGET_<NAME>_OPTS_P.
> 	(InverseMask): Ditto.
> 	* opth-gen.awk (Mask): Generate TARGET_<NAME>_P and
> 	TARGET_<NAME>_OPTS_P macro.
> 	(InverseMask): Ditto.
Doesn't this need to be updated to avoid multi-dimensional arrays in awk 
and rebased?

Jeff

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v1 2/4] RISC-V: Refactor riscv_option_override and riscv_convert_vector_bits. [NFC]
  2023-10-03  9:09 ` [PATCH v1 2/4] RISC-V: Refactor riscv_option_override and riscv_convert_vector_bits. [NFC] Kito Cheng
@ 2023-10-09 14:18   ` Jeff Law
  0 siblings, 0 replies; 9+ messages in thread
From: Jeff Law @ 2023-10-09 14:18 UTC (permalink / raw)
  To: Kito Cheng, gcc-patches, kito.cheng, palmer, rdapp, juzhe.zhong



On 10/3/23 03:09, Kito Cheng wrote:
> Allow those funciton apply from a local gcc_options rather than the
> global options.
> 
> Preparatory for target attribute, sperate this change for eaiser reivew
> since it's a NFC.
> 
> gcc/ChangeLog:
> 
> 	* config/riscv/riscv.cc (riscv_convert_vector_bits): Get setting
> 	from argument rather than get setting from global setting.
> 	(riscv_override_options_internal): New, splited from
> 	riscv_override_options, also take a gcc_options argument.
> 	(riscv_option_override): Splited most part to
> 	riscv_override_options_internal.
OK once prerequisites are approved and installed.

jeff

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v1 1/4] options: Define TARGET_<NAME>_P and TARGET_<NAME>_OPTS_P macro for Mask and InverseMask
  2023-10-09 14:16   ` Jeff Law
@ 2023-10-09 20:03     ` Kito Cheng
  0 siblings, 0 replies; 9+ messages in thread
From: Kito Cheng @ 2023-10-09 20:03 UTC (permalink / raw)
  To: Jeff Law; +Cc: Kito Cheng, gcc-patches, palmer, rdapp, juzhe.zhong

> Doesn't this need to be updated to avoid multi-dimensional arrays in awk
> and rebased?

Oh, yeah, I should update that, it's post before that issue reported,
let me send v2 soooon :P

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2023-10-09 20:03 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-10-03  9:09 Kito Cheng
2023-10-03  9:09 ` [PATCH v1 1/4] options: Define TARGET_<NAME>_P and TARGET_<NAME>_OPTS_P macro for Mask and InverseMask Kito Cheng
2023-10-09 14:16   ` Jeff Law
2023-10-09 20:03     ` Kito Cheng
2023-10-03  9:09 ` [PATCH v1 2/4] RISC-V: Refactor riscv_option_override and riscv_convert_vector_bits. [NFC] Kito Cheng
2023-10-09 14:18   ` Jeff Law
2023-10-03  9:09 ` [PATCH v1 3/4] RISC-V: Extend riscv_subset_list, preparatory for target attribute support Kito Cheng
2023-10-03  9:09 ` [PATCH v1 4/4] RISC-V: Implement target attribute Kito Cheng
2023-10-03  9:11 ` Kito Cheng

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).