diff mbox

Move target independent code to support target_clones attributes from i386 to common code

Message ID 20170510224004.GA2797@ibm-tiger.the-meissners.org
State New
Headers show

Commit Message

Michael Meissner May 10, 2017, 10:40 p.m. UTC
As I mentioned in the mail message:
https://gcc.gnu.org/ml/gcc/2017-05/msg00060.html

I'm working on adding the target_clones attribute support to the PowerPC.  I
have an implementation right now, but I want to iterate on it somewhat.

In doing the patch, I noticed there were several functions that were added to
the i386 port to enable target_clones that I could use without modification in
the PowerPC.  This patch moves these functions from i386.c to attribs.c.

I made a few changes to the functions to in order to make these common code:

    1)	I removed 'static' on the declarations.

    2)	I renamed 'ix86_function_versions' to 'common_function_versions' and
	changed TARGET_OPTION_FUNCTION_VERSIONS to point to that.

    3)	I renamed make_name to make_unique_name.

    4)	I removed a trailing space in one of the functions.

I have done bootstraps and make check tests on both x86_64 and PowerPC and
there were no regressions.  On the PowerPC, I included my initial
implementation of the target_clones support, but those patches are not part of
this patch submission.

Can I check this into the trunk?

2017-05-10  Michael Meissner  <meissner@linux.vnet.ibm.com>

	* attribs.h (sorted_attr_string): Move machine independent
	functions for target clone support from the i386 port to common
	code.  Rename ix86_function_versions to common_function_versions.
	Rename make_name to make_unique_name.
	(common_function_versions): Likewise.
	(make_unique_name): Likewise.
	(make_dispatcher_decl): Likewise.
	(is_function_default_version): Likewise.
	* attribs.c (attr_strcmp): Likewise.
	(sorted_attr_string): Likewise.
	(common_function_versions): Likewise.
	(make_unique_name): Likewise.
	(make_dispatcher_decl): Likewise.
	(is_function_default_version): Likewise.
	* config/i386/i386.c (attr_strcmp): Likewise.
	(sorted_attr_string): Likewise.
	(ix86_function_versions): Likewise.
	(make_name): Likewise.
	(make_dispatcher_decl): Likewise.
	(is_function_default_version): Likewise.
	(TARGET_OPTION_FUNCTION_VERSIONS): Update target function hook.

Comments

Jeff Law May 11, 2017, 5:23 p.m. UTC | #1
On 05/10/2017 04:40 PM, Michael Meissner wrote:
> As I mentioned in the mail message:
> https://gcc.gnu.org/ml/gcc/2017-05/msg00060.html
> 
> I'm working on adding the target_clones attribute support to the PowerPC.  I
> have an implementation right now, but I want to iterate on it somewhat.
> 
> In doing the patch, I noticed there were several functions that were added to
> the i386 port to enable target_clones that I could use without modification in
> the PowerPC.  This patch moves these functions from i386.c to attribs.c.
> 
> I made a few changes to the functions to in order to make these common code:
> 
>      1)	I removed 'static' on the declarations.
> 
>      2)	I renamed 'ix86_function_versions' to 'common_function_versions' and
> 	changed TARGET_OPTION_FUNCTION_VERSIONS to point to that.
> 
>      3)	I renamed make_name to make_unique_name.
> 
>      4)	I removed a trailing space in one of the functions.
> 
> I have done bootstraps and make check tests on both x86_64 and PowerPC and
> there were no regressions.  On the PowerPC, I included my initial
> implementation of the target_clones support, but those patches are not part of
> this patch submission.
> 
> Can I check this into the trunk?
> 
> 2017-05-10  Michael Meissner  <meissner@linux.vnet.ibm.com>
> 
> 	* attribs.h (sorted_attr_string): Move machine independent
> 	functions for target clone support from the i386 port to common
> 	code.  Rename ix86_function_versions to common_function_versions.
> 	Rename make_name to make_unique_name.
> 	(common_function_versions): Likewise.
> 	(make_unique_name): Likewise.
> 	(make_dispatcher_decl): Likewise.
> 	(is_function_default_version): Likewise.
> 	* attribs.c (attr_strcmp): Likewise.
> 	(sorted_attr_string): Likewise.
> 	(common_function_versions): Likewise.
> 	(make_unique_name): Likewise.
> 	(make_dispatcher_decl): Likewise.
> 	(is_function_default_version): Likewise.
> 	* config/i386/i386.c (attr_strcmp): Likewise.
> 	(sorted_attr_string): Likewise.
> 	(ix86_function_versions): Likewise.
> 	(make_name): Likewise.
> 	(make_dispatcher_decl): Likewise.
> 	(is_function_default_version): Likewise.
> 	(TARGET_OPTION_FUNCTION_VERSIONS): Update target function hook.
> 
OK.
jeff
diff mbox

Patch

Index: gcc/attribs.h
===================================================================
--- gcc/attribs.h	(revision 247770)
+++ gcc/attribs.h	(working copy)
@@ -41,4 +41,10 @@  extern tree make_attribute (const char *
 extern struct scoped_attributes* register_scoped_attributes (const struct attribute_spec *,
 							     const char *);
 
+extern char *sorted_attr_string (tree);
+extern bool common_function_versions (tree, tree);
+extern char *make_unique_name (tree, const char *, bool);
+extern tree make_dispatcher_decl (const tree);
+extern bool is_function_default_version (const tree);
+
 #endif // GCC_ATTRIBS_H
Index: gcc/attribs.c
===================================================================
--- gcc/attribs.c	(revision 247770)
+++ gcc/attribs.c	(working copy)
@@ -690,3 +690,242 @@  make_attribute (const char *name, const 
   attr = tree_cons (attr_name, attr_args, chain);
   return attr;
 }
+
+
+/* Common functions used for target clone support.  */
+
+/* Comparator function to be used in qsort routine to sort attribute
+   specification strings to "target".  */
+
+static int
+attr_strcmp (const void *v1, const void *v2)
+{
+  const char *c1 = *(char *const*)v1;
+  const char *c2 = *(char *const*)v2;
+  return strcmp (c1, c2);
+}
+
+/* ARGLIST is the argument to target attribute.  This function tokenizes
+   the comma separated arguments, sorts them and returns a string which
+   is a unique identifier for the comma separated arguments.   It also
+   replaces non-identifier characters "=,-" with "_".  */
+
+char *
+sorted_attr_string (tree arglist)
+{
+  tree arg;
+  size_t str_len_sum = 0;
+  char **args = NULL;
+  char *attr_str, *ret_str;
+  char *attr = NULL;
+  unsigned int argnum = 1;
+  unsigned int i;
+
+  for (arg = arglist; arg; arg = TREE_CHAIN (arg))
+    {
+      const char *str = TREE_STRING_POINTER (TREE_VALUE (arg));
+      size_t len = strlen (str);
+      str_len_sum += len + 1;
+      if (arg != arglist)
+	argnum++;
+      for (i = 0; i < strlen (str); i++)
+	if (str[i] == ',')
+	  argnum++;
+    }
+
+  attr_str = XNEWVEC (char, str_len_sum);
+  str_len_sum = 0;
+  for (arg = arglist; arg; arg = TREE_CHAIN (arg))
+    {
+      const char *str = TREE_STRING_POINTER (TREE_VALUE (arg));
+      size_t len = strlen (str);
+      memcpy (attr_str + str_len_sum, str, len);
+      attr_str[str_len_sum + len] = TREE_CHAIN (arg) ? ',' : '\0';
+      str_len_sum += len + 1;
+    }
+
+  /* Replace "=,-" with "_".  */
+  for (i = 0; i < strlen (attr_str); i++)
+    if (attr_str[i] == '=' || attr_str[i]== '-')
+      attr_str[i] = '_';
+
+  if (argnum == 1)
+    return attr_str;
+
+  args = XNEWVEC (char *, argnum);
+
+  i = 0;
+  attr = strtok (attr_str, ",");
+  while (attr != NULL)
+    {
+      args[i] = attr;
+      i++;
+      attr = strtok (NULL, ",");
+    }
+
+  qsort (args, argnum, sizeof (char *), attr_strcmp);
+
+  ret_str = XNEWVEC (char, str_len_sum);
+  str_len_sum = 0;
+  for (i = 0; i < argnum; i++)
+    {
+      size_t len = strlen (args[i]);
+      memcpy (ret_str + str_len_sum, args[i], len);
+      ret_str[str_len_sum + len] = i < argnum - 1 ? '_' : '\0';
+      str_len_sum += len + 1;
+    }
+
+  XDELETEVEC (args);
+  XDELETEVEC (attr_str);
+  return ret_str;
+}
+
+
+/* This function returns true if FN1 and FN2 are versions of the same function,
+   that is, the target strings of the function decls are different.  This assumes
+   that FN1 and FN2 have the same signature.  */
+
+bool
+common_function_versions (tree fn1, tree fn2)
+{
+  tree attr1, attr2;
+  char *target1, *target2;
+  bool result;
+
+  if (TREE_CODE (fn1) != FUNCTION_DECL
+      || TREE_CODE (fn2) != FUNCTION_DECL)
+    return false;
+
+  attr1 = lookup_attribute ("target", DECL_ATTRIBUTES (fn1));
+  attr2 = lookup_attribute ("target", DECL_ATTRIBUTES (fn2));
+
+  /* At least one function decl should have the target attribute specified.  */
+  if (attr1 == NULL_TREE && attr2 == NULL_TREE)
+    return false;
+
+  /* Diagnose missing target attribute if one of the decls is already
+     multi-versioned.  */
+  if (attr1 == NULL_TREE || attr2 == NULL_TREE)
+    {
+      if (DECL_FUNCTION_VERSIONED (fn1) || DECL_FUNCTION_VERSIONED (fn2))
+	{
+	  if (attr2 != NULL_TREE)
+	    {
+	      std::swap (fn1, fn2);
+	      attr1 = attr2;
+	    }
+	  error_at (DECL_SOURCE_LOCATION (fn2),
+		    "missing %<target%> attribute for multi-versioned %qD",
+		    fn2);
+	  inform (DECL_SOURCE_LOCATION (fn1),
+		  "previous declaration of %qD", fn1);
+	  /* Prevent diagnosing of the same error multiple times.  */
+	  DECL_ATTRIBUTES (fn2)
+	    = tree_cons (get_identifier ("target"),
+			 copy_node (TREE_VALUE (attr1)),
+			 DECL_ATTRIBUTES (fn2));
+	}
+      return false;
+    }
+
+  target1 = sorted_attr_string (TREE_VALUE (attr1));
+  target2 = sorted_attr_string (TREE_VALUE (attr2));
+
+  /* The sorted target strings must be different for fn1 and fn2
+     to be versions.  */
+  if (strcmp (target1, target2) == 0)
+    result = false;
+  else
+    result = true;
+
+  XDELETEVEC (target1);
+  XDELETEVEC (target2);
+
+  return result;
+}
+
+/* Return a new name by appending SUFFIX to the DECL name.  If make_unique
+   is true, append the full path name of the source file.  */
+
+char *
+make_unique_name (tree decl, const char *suffix, bool make_unique)
+{
+  char *global_var_name;
+  int name_len;
+  const char *name;
+  const char *unique_name = NULL;
+
+  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+
+  /* Get a unique name that can be used globally without any chances
+     of collision at link time.  */
+  if (make_unique)
+    unique_name = IDENTIFIER_POINTER (get_file_function_name ("\0"));
+
+  name_len = strlen (name) + strlen (suffix) + 2;
+
+  if (make_unique)
+    name_len += strlen (unique_name) + 1;
+  global_var_name = XNEWVEC (char, name_len);
+
+  /* Use '.' to concatenate names as it is demangler friendly.  */
+  if (make_unique)
+    snprintf (global_var_name, name_len, "%s.%s.%s", name, unique_name,
+	      suffix);
+  else
+    snprintf (global_var_name, name_len, "%s.%s", name, suffix);
+
+  return global_var_name;
+}
+
+/* Make a dispatcher declaration for the multi-versioned function DECL.
+   Calls to DECL function will be replaced with calls to the dispatcher
+   by the front-end.  Return the decl created.  */
+
+tree
+make_dispatcher_decl (const tree decl)
+{
+  tree func_decl;
+  char *func_name;
+  tree fn_type, func_type;
+  bool is_uniq = false;
+
+  if (TREE_PUBLIC (decl) == 0)
+    is_uniq = true;
+
+  func_name = make_unique_name (decl, "ifunc", is_uniq);
+
+  fn_type = TREE_TYPE (decl);
+  func_type = build_function_type (TREE_TYPE (fn_type),
+				   TYPE_ARG_TYPES (fn_type));
+  
+  func_decl = build_fn_decl (func_name, func_type);
+  XDELETEVEC (func_name);
+  TREE_USED (func_decl) = 1;
+  DECL_CONTEXT (func_decl) = NULL_TREE;
+  DECL_INITIAL (func_decl) = error_mark_node;
+  DECL_ARTIFICIAL (func_decl) = 1;
+  /* Mark this func as external, the resolver will flip it again if
+     it gets generated.  */
+  DECL_EXTERNAL (func_decl) = 1;
+  /* This will be of type IFUNCs have to be externally visible.  */
+  TREE_PUBLIC (func_decl) = 1;
+
+  return func_decl;  
+}
+
+/* Returns true if decl is multi-versioned and DECL is the default function,
+   that is it is not tagged with target specific optimization.  */
+
+bool
+is_function_default_version (const tree decl)
+{
+  if (TREE_CODE (decl) != FUNCTION_DECL
+      || !DECL_FUNCTION_VERSIONED (decl))
+    return false;
+  tree attr = lookup_attribute ("target", DECL_ATTRIBUTES (decl));
+  gcc_assert (attr);
+  attr = TREE_VALUE (TREE_VALUE (attr));
+  return (TREE_CODE (attr) == STRING_CST
+	  && strcmp (TREE_STRING_POINTER (attr), "default") == 0);
+}
Index: gcc/config/i386/i386.c
===================================================================
--- gcc/config/i386/i386.c	(revision 247770)
+++ gcc/config/i386/i386.c	(working copy)
@@ -32898,92 +32898,6 @@  dispatch_function_versions (tree dispatc
   return 0;
 }
 
-/* Comparator function to be used in qsort routine to sort attribute
-   specification strings to "target".  */
-
-static int
-attr_strcmp (const void *v1, const void *v2)
-{
-  const char *c1 = *(char *const*)v1;
-  const char *c2 = *(char *const*)v2;
-  return strcmp (c1, c2);
-}
-
-/* ARGLIST is the argument to target attribute.  This function tokenizes
-   the comma separated arguments, sorts them and returns a string which
-   is a unique identifier for the comma separated arguments.   It also
-   replaces non-identifier characters "=,-" with "_".  */
-
-static char *
-sorted_attr_string (tree arglist)
-{
-  tree arg;
-  size_t str_len_sum = 0;
-  char **args = NULL;
-  char *attr_str, *ret_str;
-  char *attr = NULL;
-  unsigned int argnum = 1;
-  unsigned int i;
-
-  for (arg = arglist; arg; arg = TREE_CHAIN (arg))
-    {
-      const char *str = TREE_STRING_POINTER (TREE_VALUE (arg));
-      size_t len = strlen (str);
-      str_len_sum += len + 1;
-      if (arg != arglist)
-	argnum++;
-      for (i = 0; i < strlen (str); i++)
-	if (str[i] == ',')
-	  argnum++;
-    }
-
-  attr_str = XNEWVEC (char, str_len_sum);
-  str_len_sum = 0;
-  for (arg = arglist; arg; arg = TREE_CHAIN (arg))
-    {
-      const char *str = TREE_STRING_POINTER (TREE_VALUE (arg));
-      size_t len = strlen (str);
-      memcpy (attr_str + str_len_sum, str, len);
-      attr_str[str_len_sum + len] = TREE_CHAIN (arg) ? ',' : '\0';
-      str_len_sum += len + 1;
-    }
-
-  /* Replace "=,-" with "_".  */
-  for (i = 0; i < strlen (attr_str); i++)
-    if (attr_str[i] == '=' || attr_str[i]== '-')
-      attr_str[i] = '_';
-
-  if (argnum == 1)
-    return attr_str;
-
-  args = XNEWVEC (char *, argnum);
-
-  i = 0;
-  attr = strtok (attr_str, ",");
-  while (attr != NULL)
-    {
-      args[i] = attr;
-      i++;
-      attr = strtok (NULL, ",");
-    }
-
-  qsort (args, argnum, sizeof (char *), attr_strcmp);
-
-  ret_str = XNEWVEC (char, str_len_sum);
-  str_len_sum = 0;
-  for (i = 0; i < argnum; i++)
-    {
-      size_t len = strlen (args[i]);
-      memcpy (ret_str + str_len_sum, args[i], len);
-      ret_str[str_len_sum + len] = i < argnum - 1 ? '_' : '\0';
-      str_len_sum += len + 1;
-    }
-
-  XDELETEVEC (args);
-  XDELETEVEC (attr_str);
-  return ret_str;
-}
-
 /* This function changes the assembler name for functions that are
    versions.  If DECL is a function version and has a "target"
    attribute, it appends the attribute string to its assembler name.  */
@@ -33033,68 +32947,6 @@  ix86_mangle_function_version_assembler_n
   return ret;
 }
 
-/* This function returns true if FN1 and FN2 are versions of the same function,
-   that is, the target strings of the function decls are different.  This assumes
-   that FN1 and FN2 have the same signature.  */
-
-static bool
-ix86_function_versions (tree fn1, tree fn2)
-{
-  tree attr1, attr2;
-  char *target1, *target2;
-  bool result;
-
-  if (TREE_CODE (fn1) != FUNCTION_DECL
-      || TREE_CODE (fn2) != FUNCTION_DECL)
-    return false;
-
-  attr1 = lookup_attribute ("target", DECL_ATTRIBUTES (fn1));
-  attr2 = lookup_attribute ("target", DECL_ATTRIBUTES (fn2));
-
-  /* At least one function decl should have the target attribute specified.  */
-  if (attr1 == NULL_TREE && attr2 == NULL_TREE)
-    return false;
-
-  /* Diagnose missing target attribute if one of the decls is already
-     multi-versioned.  */
-  if (attr1 == NULL_TREE || attr2 == NULL_TREE)
-    {
-      if (DECL_FUNCTION_VERSIONED (fn1) || DECL_FUNCTION_VERSIONED (fn2))
-	{
-	  if (attr2 != NULL_TREE)
-	    {
-	      std::swap (fn1, fn2);
-	      attr1 = attr2;
-	    }
-	  error_at (DECL_SOURCE_LOCATION (fn2),
-		    "missing %<target%> attribute for multi-versioned %qD",
-		    fn2);
-	  inform (DECL_SOURCE_LOCATION (fn1),
-		  "previous declaration of %qD", fn1);
-	  /* Prevent diagnosing of the same error multiple times.  */
-	  DECL_ATTRIBUTES (fn2)
-	    = tree_cons (get_identifier ("target"),
-			 copy_node (TREE_VALUE (attr1)),
-			 DECL_ATTRIBUTES (fn2));
-	}
-      return false;
-    }
-
-  target1 = sorted_attr_string (TREE_VALUE (attr1));
-  target2 = sorted_attr_string (TREE_VALUE (attr2));
-
-  /* The sorted target strings must be different for fn1 and fn2
-     to be versions.  */
-  if (strcmp (target1, target2) == 0)
-    result = false;
-  else
-    result = true;
-
-  XDELETEVEC (target1);
-  XDELETEVEC (target2); 
-  
-  return result;
-}
 
 static tree 
 ix86_mangle_decl_assembler_name (tree decl, tree id)
@@ -33110,96 +32962,6 @@  ix86_mangle_decl_assembler_name (tree de
   return id;
 }
 
-/* Return a new name by appending SUFFIX to the DECL name.  If make_unique
-   is true, append the full path name of the source file.  */
-
-static char *
-make_name (tree decl, const char *suffix, bool make_unique)
-{
-  char *global_var_name;
-  int name_len;
-  const char *name;
-  const char *unique_name = NULL;
-
-  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-
-  /* Get a unique name that can be used globally without any chances
-     of collision at link time.  */
-  if (make_unique)
-    unique_name = IDENTIFIER_POINTER (get_file_function_name ("\0"));
-
-  name_len = strlen (name) + strlen (suffix) + 2;
-
-  if (make_unique)
-    name_len += strlen (unique_name) + 1;
-  global_var_name = XNEWVEC (char, name_len);
-
-  /* Use '.' to concatenate names as it is demangler friendly.  */
-  if (make_unique)
-    snprintf (global_var_name, name_len, "%s.%s.%s", name, unique_name,
-	      suffix);
-  else
-    snprintf (global_var_name, name_len, "%s.%s", name, suffix);
-
-  return global_var_name;
-}
-
-#if defined (ASM_OUTPUT_TYPE_DIRECTIVE)
-
-/* Make a dispatcher declaration for the multi-versioned function DECL.
-   Calls to DECL function will be replaced with calls to the dispatcher
-   by the front-end.  Return the decl created.  */
-
-static tree
-make_dispatcher_decl (const tree decl)
-{
-  tree func_decl;
-  char *func_name;
-  tree fn_type, func_type;
-  bool is_uniq = false;
-
-  if (TREE_PUBLIC (decl) == 0)
-    is_uniq = true;
-
-  func_name = make_name (decl, "ifunc", is_uniq);
-
-  fn_type = TREE_TYPE (decl);
-  func_type = build_function_type (TREE_TYPE (fn_type),
-				   TYPE_ARG_TYPES (fn_type));
-  
-  func_decl = build_fn_decl (func_name, func_type);
-  XDELETEVEC (func_name);
-  TREE_USED (func_decl) = 1;
-  DECL_CONTEXT (func_decl) = NULL_TREE;
-  DECL_INITIAL (func_decl) = error_mark_node;
-  DECL_ARTIFICIAL (func_decl) = 1;
-  /* Mark this func as external, the resolver will flip it again if
-     it gets generated.  */
-  DECL_EXTERNAL (func_decl) = 1;
-  /* This will be of type IFUNCs have to be externally visible.  */
-  TREE_PUBLIC (func_decl) = 1;
-
-  return func_decl;  
-}
-
-#endif
-
-/* Returns true if decl is multi-versioned and DECL is the default function,
-   that is it is not tagged with target specific optimization.  */
-
-static bool
-is_function_default_version (const tree decl)
-{
-  if (TREE_CODE (decl) != FUNCTION_DECL
-      || !DECL_FUNCTION_VERSIONED (decl))
-    return false;
-  tree attr = lookup_attribute ("target", DECL_ATTRIBUTES (decl));
-  gcc_assert (attr);
-  attr = TREE_VALUE (TREE_VALUE (attr));
-  return (TREE_CODE (attr) == STRING_CST
-	  && strcmp (TREE_STRING_POINTER (attr), "default") == 0);
-}
-
 /* Make a dispatcher declaration for the multi-versioned function DECL.
    Calls to DECL function will be replaced with calls to the dispatcher
    by the front-end.  Returns the decl of the dispatcher function.  */
@@ -33320,7 +33082,7 @@  make_resolver_func (const tree default_d
      to be externally visible for the loader to find it.  So, appending
      the filename will prevent conflicts with a resolver function from
      another module which is based on the same version name.  */
-  resolver_name = make_name (default_decl, "resolver", is_uniq);
+  resolver_name = make_unique_name (default_decl, "resolver", is_uniq);
 
   /* The resolver function should return a (void *). */
   type = build_function_type_list (ptr_type_node, NULL_TREE);
@@ -52238,7 +52000,7 @@  ix86_run_selftests (void)
 #define TARGET_OPTION_PRINT ix86_function_specific_print
 
 #undef TARGET_OPTION_FUNCTION_VERSIONS
-#define TARGET_OPTION_FUNCTION_VERSIONS ix86_function_versions
+#define TARGET_OPTION_FUNCTION_VERSIONS common_function_versions
 
 #undef TARGET_CAN_INLINE_P
 #define TARGET_CAN_INLINE_P ix86_can_inline_p