From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 30401 invoked by alias); 10 May 2017 22:40:12 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 30320 invoked by uid 89); 10 May 2017 22:40:11 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-9.6 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_2,GIT_PATCH_3,KAM_ASCII_DIVIDERS,KAM_LAZY_DOMAIN_SECURITY,KAM_MANYTO,RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.2 spammy=sorts X-HELO: mx0a-001b2d01.pphosted.com Received: from mx0a-001b2d01.pphosted.com (HELO mx0a-001b2d01.pphosted.com) (148.163.156.1) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 10 May 2017 22:40:08 +0000 Received: from pps.filterd (m0098399.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.20/8.16.0.20) with SMTP id v4AMdPEU058549 for ; Wed, 10 May 2017 18:40:09 -0400 Received: from e18.ny.us.ibm.com (e18.ny.us.ibm.com [129.33.205.208]) by mx0a-001b2d01.pphosted.com with ESMTP id 2ac47pp5ws-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Wed, 10 May 2017 18:40:09 -0400 Received: from localhost by e18.ny.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Wed, 10 May 2017 18:40:08 -0400 Received: from b01cxnp23033.gho.pok.ibm.com (9.57.198.28) by e18.ny.us.ibm.com (146.89.104.205) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Wed, 10 May 2017 18:40:05 -0400 Received: from b01ledav004.gho.pok.ibm.com (b01ledav004.gho.pok.ibm.com [9.57.199.109]) by b01cxnp23033.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id v4AMeAGw328130; Wed, 10 May 2017 22:40:10 GMT Received: from b01ledav004.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 00C8C112040; Wed, 10 May 2017 18:40:10 -0400 (EDT) Received: from ibm-tiger.the-meissners.org (unknown [9.32.77.111]) by b01ledav004.gho.pok.ibm.com (Postfix) with ESMTP id CC759112034; Wed, 10 May 2017 18:40:09 -0400 (EDT) Received: by ibm-tiger.the-meissners.org (Postfix, from userid 500) id 8ED7E47418; Wed, 10 May 2017 18:40:04 -0400 (EDT) Date: Wed, 10 May 2017 23:05:00 -0000 From: Michael Meissner To: GCC Patches , Segher Boessenkool , David Edelsohn , Jan Hubicka , Uros Bizjak , Kirill Yukhin Subject: [PATCH] Move target independent code to support target_clones attributes from i386 to common code Mail-Followup-To: Michael Meissner , GCC Patches , Segher Boessenkool , David Edelsohn , Jan Hubicka , Uros Bizjak , Kirill Yukhin MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="SUOF0GtieIMvvwua" Content-Disposition: inline User-Agent: Mutt/1.5.20 (2009-12-10) X-TM-AS-GCONF: 00 x-cbid: 17051022-0044-0000-0000-00000328759D X-IBM-SpamModules-Scores: X-IBM-SpamModules-Versions: BY=3.00007044; HX=3.00000240; KW=3.00000007; PH=3.00000004; SC=3.00000210; SDB=6.00858855; UDB=6.00425601; IPR=6.00638331; BA=6.00005342; NDR=6.00000001; ZLA=6.00000005; ZF=6.00000009; ZB=6.00000000; ZP=6.00000000; ZH=6.00000000; ZU=6.00000002; MB=3.00015403; XFM=3.00000015; UTC=2017-05-10 22:40:08 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 17051022-0045-0000-0000-000007568120 Message-Id: <20170510224004.GA2797@ibm-tiger.the-meissners.org> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:,, definitions=2017-05-10_19:,, signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 suspectscore=0 malwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1703280000 definitions=main-1705100153 X-IsSubscribed: yes X-SW-Source: 2017-05/txt/msg00835.txt.bz2 --SUOF0GtieIMvvwua Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-length: 2207 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 * 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. -- Michael Meissner, IBM IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA email: meissner@linux.vnet.ibm.com, phone: +1 (978) 899-4797 --SUOF0GtieIMvvwua Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="clone.patch01b" Content-length: 16484 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 % 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 % 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 --SUOF0GtieIMvvwua--