From 1b062c1ac195e221ff72e03b37d630a4fa1f6dbe Mon Sep 17 00:00:00 2001 From: Michael Meissner Date: Thu, 11 May 2017 21:51:07 +0000 Subject: [PATCH] attribs.h (sorted_attr_string): Move machine independent functions for target clone support from the i386 port... 2017-05-11 Michael Meissner * 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. From-SVN: r247932 --- gcc/ChangeLog | 24 ++++ gcc/attribs.c | 239 ++++++++++++++++++++++++++++++++++++++++ gcc/attribs.h | 6 + gcc/config/i386/i386.c | 242 +---------------------------------------- 4 files changed, 271 insertions(+), 240 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 24af7d1711b..da403cd8b49 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,27 @@ +2017-05-11 Michael Meissner + + * 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. + 2017-05-11 Bill Schmidt PR target/80695 diff --git a/gcc/attribs.c b/gcc/attribs.c index 55b21271b39..4ba0eab8899 100644 --- a/gcc/attribs.c +++ b/gcc/attribs.c @@ -690,3 +690,242 @@ make_attribute (const char *name, const char *arg_name, tree chain) 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 % 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); +} diff --git a/gcc/attribs.h b/gcc/attribs.h index 9d3741c1305..7f13332700e 100644 --- a/gcc/attribs.h +++ b/gcc/attribs.h @@ -41,4 +41,10 @@ extern tree make_attribute (const char *, const char *, tree); 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 diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index de97d3c322f..7e8cdb9602a 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -32898,92 +32898,6 @@ dispatch_function_versions (tree dispatch_decl, 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_name (tree decl, tree id) 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 % 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 decl, tree id) 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_decl, 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 -- 2.30.2