diff mbox series

[v4,4/8] RISC-V: Implement TARGET_OPTION_VALID_VERSION_ATTRIBUTE_P

Message ID tencent_D28231DA658E62B83631B521498D9D7CB808@qq.com
State New
Headers show
Series RISC-V: Add Function Multi-Versioning support | expand

Commit Message

Yangyu Chen Nov. 1, 2024, 8:59 p.m. UTC
This patch implements the TARGET_OPTION_VALID_VERSION_ATTRIBUTE_P for
RISC-V. This hook is used to process attribute
((target_version ("..."))).

As it is the first patch which introduces the target_version attribute,
we also set TARGET_HAS_FMV_TARGET_ATTRIBUTE to 0 to use "target_version"
for function versioning.

Co-Developed-by: Hank Chang <hank.chang@sifive.com>
Signed-off-by: Yangyu Chen <cyy@cyyself.name>

gcc/ChangeLog:

	* config/riscv/riscv-protos.h
	(riscv_process_target_attr): Remove as it is not used.
	(riscv_option_valid_version_attribute_p): Declare.
	(riscv_process_target_version_attr): Declare.
	* config/riscv/riscv-target-attr.cc
	(riscv_target_attrs): Renamed from riscv_attributes.
	(riscv_target_version_attrs): New attributes for target_version.
	(riscv_process_one_target_attr): New arguments to select attrs.
	(riscv_process_target_attr): Likewise.
	(riscv_option_valid_attribute_p): Likewise.
	(riscv_process_target_version_attr): New function.
	(riscv_option_valid_version_attribute_p): New function.
	* config/riscv/riscv.cc
	(TARGET_OPTION_VALID_VERSION_ATTRIBUTE_P): Implement it.
	* config/riscv/riscv.h (TARGET_HAS_FMV_TARGET_ATTRIBUTE): Define
	it to 0 to use "target_version" for function versioning.
---
 gcc/config/riscv/riscv-protos.h       |   4 +-
 gcc/config/riscv/riscv-target-attr.cc | 118 +++++++++++++++++++++++---
 gcc/config/riscv/riscv.cc             |   4 +
 gcc/config/riscv/riscv.h              |   2 +
 4 files changed, 115 insertions(+), 13 deletions(-)
diff mbox series

Patch

diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 4ed04321d32..500b357f6eb 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -806,7 +806,9 @@  void riscv_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int);
 extern bool
 riscv_option_valid_attribute_p (tree, tree, tree, int);
 extern bool
-riscv_process_target_attr (const char *, location_t);
+riscv_option_valid_version_attribute_p (tree, tree, tree, int);
+extern bool
+riscv_process_target_version_attr (tree, location_t);
 extern void
 riscv_override_options_internal (struct gcc_options *);
 extern void riscv_option_override (void);
diff --git a/gcc/config/riscv/riscv-target-attr.cc b/gcc/config/riscv/riscv-target-attr.cc
index 293d5321215..2979d63a011 100644
--- a/gcc/config/riscv/riscv-target-attr.cc
+++ b/gcc/config/riscv/riscv-target-attr.cc
@@ -82,10 +82,16 @@  struct riscv_attribute_info
 
 /* The target attributes that we support.  */
 
-static const struct riscv_attribute_info riscv_attributes[]
+static const struct riscv_attribute_info riscv_target_attrs[]
   = {{"arch", &riscv_target_attr_parser::handle_arch},
      {"cpu", &riscv_target_attr_parser::handle_cpu},
-     {"tune", &riscv_target_attr_parser::handle_tune}};
+     {"tune", &riscv_target_attr_parser::handle_tune},
+     {NULL, NULL}};
+
+static const struct riscv_attribute_info riscv_target_version_attrs[]
+  = {{"arch", &riscv_target_attr_parser::handle_arch},
+     {"priority", &riscv_target_attr_parser::handle_priority},
+     {NULL, NULL}};
 
 bool
 riscv_target_attr_parser::parse_arch (const char *str)
@@ -268,7 +274,8 @@  riscv_target_attr_parser::update_settings (struct gcc_options *opts) const
 static bool
 riscv_process_one_target_attr (char *arg_str,
 			       location_t loc,
-			       riscv_target_attr_parser &attr_parser)
+			       riscv_target_attr_parser &attr_parser,
+			       const struct riscv_attribute_info *attrs)
 {
   size_t len = strlen (arg_str);
 
@@ -295,15 +302,17 @@  riscv_process_one_target_attr (char *arg_str,
 
   arg[0] = '\0';
   ++arg;
-  for (const auto &attr : riscv_attributes)
+  for (const auto *attr = attrs;
+       attr->name;
+       ++attr)
     {
       /* 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)
+      if (strncmp (str_to_check, attr->name, strlen (attr->name)) != 0)
 	continue;
 
-      return (&attr_parser->*attr.handler) (arg);
+      return (&attr_parser->*attr->handler) (arg);
     }
 
   error_at (loc, "Got unknown attribute %<target(\"%s\")%>", str_to_check);
@@ -332,7 +341,9 @@  num_occurrences_in_str (char c, char *str)
    and update the global target options space.  */
 
 bool
-riscv_process_target_attr (const char *args, location_t loc)
+riscv_process_target_attr (const char *args,
+			   location_t loc,
+			   const struct riscv_attribute_info *attrs)
 {
   size_t len = strlen (args);
 
@@ -359,7 +370,7 @@  riscv_process_target_attr (const char *args, location_t loc)
   while (token)
     {
       num_attrs++;
-      if (!riscv_process_one_target_attr (token, loc, attr_parser))
+      if (!riscv_process_one_target_attr (token, loc, attr_parser, attrs))
 	return false;
 
       token = strtok_r (NULL, ";", &str_to_check);
@@ -382,7 +393,9 @@  riscv_process_target_attr (const char *args, location_t loc)
    and update the global target options space.  */
 
 static bool
-riscv_process_target_attr (tree args, location_t loc)
+riscv_process_target_attr (tree args,
+			   location_t loc,
+			   const struct riscv_attribute_info *attrs)
 {
   if (TREE_CODE (args) == TREE_LIST)
     {
@@ -391,7 +404,7 @@  riscv_process_target_attr (tree args, location_t loc)
 	  tree head = TREE_VALUE (args);
 	  if (head)
 	    {
-	      if (!riscv_process_target_attr (head, loc))
+	      if (!riscv_process_target_attr (head, loc, attrs))
 		return false;
 	    }
 	  args = TREE_CHAIN (args);
@@ -406,7 +419,7 @@  riscv_process_target_attr (tree args, location_t loc)
       return false;
     }
 
-  return riscv_process_target_attr (TREE_STRING_POINTER (args), loc);
+  return riscv_process_target_attr (TREE_STRING_POINTER (args), loc, attrs);
 }
 
 /* Implement TARGET_OPTION_VALID_ATTRIBUTE_P.
@@ -444,7 +457,7 @@  riscv_option_valid_attribute_p (tree fndecl, tree, tree args, int)
 			      TREE_TARGET_OPTION (target_option_default_node));
 
   /* Now we can parse the attributes and set &global_options accordingly.  */
-  ret = riscv_process_target_attr (args, loc);
+  ret = riscv_process_target_attr (args, loc, riscv_target_attrs);
   if (ret)
     {
       riscv_override_options_internal (&global_options);
@@ -457,3 +470,84 @@  riscv_option_valid_attribute_p (tree fndecl, tree, tree args, int)
   cl_target_option_restore (&global_options, &global_options_set, &cur_target);
   return ret;
 }
+
+/* Parse the tree in ARGS that contains the target_version attribute
+   information and update the global target options space.  */
+
+bool
+riscv_process_target_version_attr (tree args, location_t loc)
+{
+  if (TREE_CODE (args) == TREE_LIST)
+    {
+      if (TREE_CHAIN (args))
+	{
+	  error ("attribute %<target_version%> has multiple values");
+	  return false;
+	}
+      args = TREE_VALUE (args);
+    }
+
+  if (!args || TREE_CODE (args) != STRING_CST)
+    {
+      error ("attribute %<target_version%> argument not a string");
+      return false;
+    }
+
+  const char *str = TREE_STRING_POINTER (args);
+  if (strcmp (str, "default") == 0)
+    return true;
+
+  return riscv_process_target_attr (str, loc, riscv_target_version_attrs);
+}
+
+
+/* Implement TARGET_OPTION_VALID_VERSION_ATTRIBUTE_P.  This is used to
+   process attribute ((target_version ("..."))).  */
+
+bool
+riscv_option_valid_version_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);
+
+  /* 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)
+    {
+      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
+    cl_target_option_restore (&global_options, &global_options_set,
+			      TREE_TARGET_OPTION (target_option_current_node));
+
+  ret = riscv_process_target_version_attr (args, loc);
+
+  /* Set up any additional state.  */
+  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 0b3b2c4cba9..23062a482c2 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -13060,6 +13060,10 @@  riscv_stack_clash_protection_alloca_probe_range (void)
 #undef TARGET_C_MODE_FOR_FLOATING_TYPE
 #define TARGET_C_MODE_FOR_FLOATING_TYPE riscv_c_mode_for_floating_type
 
+#undef TARGET_OPTION_VALID_VERSION_ATTRIBUTE_P
+#define TARGET_OPTION_VALID_VERSION_ATTRIBUTE_P \
+  riscv_option_valid_version_attribute_p
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-riscv.h"
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index 2ff9c1024f3..8a8b08b6b51 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -1303,4 +1303,6 @@  extern void riscv_remove_unneeded_save_restore_calls (void);
    the target attribute.  */
 #define TARGET_CLONES_ATTR_SEPARATOR '#'
 
+#define TARGET_HAS_FMV_TARGET_ATTRIBUTE 0
+
 #endif /* ! GCC_RISCV_H */