@@ -39,6 +39,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-pretty-print.h"
#include "intl.h"
#include "gcc-urlifier.h"
+#include "cgraph.h"
/* Table of the tables of attributes (common, language, format, machine)
searched. */
@@ -1248,18 +1249,12 @@ common_function_versions (tree fn1, tree fn2)
tree
make_dispatcher_decl (const tree decl)
{
- tree func_decl;
- char *func_name;
- tree fn_type, func_type;
+ tree fn_type = TREE_TYPE (decl);
+ tree func_type = build_function_type (TREE_TYPE (fn_type),
+ TYPE_ARG_TYPES (fn_type));
+ tree func_decl = build_fn_decl (IDENTIFIER_POINTER (DECL_NAME (decl)),
+ func_type);
- func_name = xstrdup (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
-
- 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;
@@ -1269,6 +1264,34 @@ make_dispatcher_decl (const tree decl)
DECL_EXTERNAL (func_decl) = 1;
/* This will be of type IFUNCs have to be externally visible. */
TREE_PUBLIC (func_decl) = 1;
+ TREE_NOTHROW (func_decl) = TREE_NOTHROW (decl);
+
+ /* Set the decl name to avoid graph_node re-mangling it. */
+ SET_DECL_ASSEMBLER_NAME (func_decl, DECL_ASSEMBLER_NAME (decl));
+
+ cgraph_node *node = cgraph_node::get (decl);
+ gcc_assert (node);
+ cgraph_function_version_info *node_v = node->function_version ();
+ gcc_assert (node_v);
+
+ /* Set flags on the cgraph_node for the new decl. */
+ cgraph_node *func_node = cgraph_node::get_create (func_decl);
+ func_node->dispatcher_function = true;
+ func_node->definition = true;
+
+ cgraph_function_version_info *func_v
+ = func_node->insert_new_function_version ();
+ func_v->next = node_v;
+ func_v->assembler_name = node_v->assembler_name;
+
+ /* If the default node is from a target_clone, mark the dispatcher as from
+ target_clone. */
+ func_node->is_target_clone = node->is_target_clone;
+
+ /* Get the assembler name by mangling with the base assembler name. */
+ tree id = targetm.mangle_decl_assembler_name
+ (func_decl, func_v->assembler_name);
+ symtab->change_decl_assembler_name (func_decl, id);
return func_decl;
}
@@ -198,8 +198,8 @@ cgraph_node::insert_new_function_version (void)
}
/* Remove the cgraph_function_version_info node given by DECL_V. */
-static void
-delete_function_version (cgraph_function_version_info *decl_v)
+void
+cgraph_node::delete_function_version (cgraph_function_version_info *decl_v)
{
if (decl_v == NULL)
return;
@@ -1332,6 +1332,8 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node
DECL is a duplicate declaration. */
static void delete_function_version_by_decl (tree decl);
+ static void delete_function_version (cgraph_function_version_info *);
+
/* Add the function FNDECL to the call graph.
Unlike finalize_function, this function is intended to be used
by middle end and allows insertion of new function at arbitrary point
@@ -20009,7 +20009,7 @@ static aarch64_fmv_feature_datum aarch64_fmv_feature_data[] = {
#include "config/aarch64/aarch64-option-extensions.def"
};
-/* Parse a function multiversioning feature string STR, as found in a
+/* Parse a function multiversioning feature string_slice STR, as found in a
target_version or target_clones attribute.
If ISA_FLAGS is nonnull, then update it with the specified architecture
@@ -20021,37 +20021,34 @@ static aarch64_fmv_feature_datum aarch64_fmv_feature_data[] = {
the extension string is created and stored to INVALID_EXTENSION. */
static enum aarch_parse_opt_result
-aarch64_parse_fmv_features (const char *str, aarch64_feature_flags *isa_flags,
+aarch64_parse_fmv_features (string_slice str, aarch64_feature_flags *isa_flags,
aarch64_fmv_feature_mask *feature_mask,
std::string *invalid_extension)
{
if (feature_mask)
*feature_mask = 0ULL;
- if (strcmp (str, "default") == 0)
+ if (str == "default")
return AARCH_PARSE_OK;
- while (str != NULL && *str != 0)
+ gcc_assert (str.is_valid ());
+
+ while (str.is_valid ())
{
- const char *ext;
- size_t len;
+ string_slice ext;
- ext = strchr (str, '+');
+ ext = string_slice::tokenize (&str, "+");
- if (ext != NULL)
- len = ext - str;
- else
- len = strlen (str);
+ gcc_assert (ext.is_valid ());
- if (len == 0)
+ if (!ext.is_valid () || ext.empty ())
return AARCH_PARSE_MISSING_ARG;
int num_features = ARRAY_SIZE (aarch64_fmv_feature_data);
int i;
for (i = 0; i < num_features; i++)
{
- if (strlen (aarch64_fmv_feature_data[i].name) == len
- && strncmp (aarch64_fmv_feature_data[i].name, str, len) == 0)
+ if (aarch64_fmv_feature_data[i].name == ext)
{
if (isa_flags)
*isa_flags |= aarch64_fmv_feature_data[i].opt_flags;
@@ -20063,7 +20060,8 @@ aarch64_parse_fmv_features (const char *str, aarch64_feature_flags *isa_flags,
{
/* Duplicate feature. */
if (invalid_extension)
- *invalid_extension = std::string (str, len);
+ *invalid_extension
+ = std::string (ext.begin (), ext.size ());
return AARCH_PARSE_DUPLICATE_FEATURE;
}
}
@@ -20075,14 +20073,9 @@ aarch64_parse_fmv_features (const char *str, aarch64_feature_flags *isa_flags,
{
/* Feature not found in list. */
if (invalid_extension)
- *invalid_extension = std::string (str, len);
+ *invalid_extension = std::string (ext.begin (), ext.size ());
return AARCH_PARSE_INVALID_FEATURE;
}
-
- str = ext;
- if (str)
- /* Skip over the next '+'. */
- str++;
}
return AARCH_PARSE_OK;
@@ -20119,7 +20112,7 @@ aarch64_process_target_version_attr (tree args)
return false;
}
- const char *str = TREE_STRING_POINTER (args);
+ string_slice str = TREE_STRING_POINTER (args);
enum aarch_parse_opt_result parse_res;
auto isa_flags = aarch64_asm_isa_flags;
@@ -20143,13 +20136,13 @@ aarch64_process_target_version_attr (tree args)
case AARCH_PARSE_INVALID_FEATURE:
error ("invalid feature modifier %qs of value %qs in "
"%<target_version%> attribute", invalid_extension.c_str (),
- str);
+ TREE_STRING_POINTER (args));
break;
case AARCH_PARSE_DUPLICATE_FEATURE:
error ("duplicate feature modifier %qs of value %qs in "
"%<target_version%> attribute", invalid_extension.c_str (),
- str);
+ TREE_STRING_POINTER (args));
break;
default:
@@ -20221,13 +20214,14 @@ get_feature_mask_for_version (tree decl)
if (version_attr == NULL)
return 0;
- const char *version_string = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE
- (version_attr)));
+ string_slice version_string
+ = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (version_attr)));
+
enum aarch_parse_opt_result parse_res;
aarch64_fmv_feature_mask feature_mask;
- parse_res = aarch64_parse_fmv_features (version_string, NULL, &feature_mask,
- NULL);
+ parse_res = aarch64_parse_fmv_features (version_string, NULL,
+ &feature_mask, NULL);
/* We should have detected any errors before getting here. */
gcc_assert (parse_res == AARCH_PARSE_OK);
@@ -20322,36 +20316,33 @@ tree
aarch64_mangle_decl_assembler_name (tree decl, tree id)
{
/* For function version, add the target suffix to the assembler name. */
- if (TREE_CODE (decl) == FUNCTION_DECL
- && DECL_FUNCTION_VERSIONED (decl))
+ if (TREE_CODE (decl) == FUNCTION_DECL)
{
- aarch64_fmv_feature_mask feature_mask = get_feature_mask_for_version (decl);
-
- std::string name = IDENTIFIER_POINTER (id);
-
- /* For the default version, append ".default". */
- if (feature_mask == 0ULL)
+ cgraph_node *node = cgraph_node::get (decl);
+ if (node && node->dispatcher_function)
+ return id;
+ else if (node && node->dispatcher_resolver_function)
+ return clone_identifier (id, "resolver");
+ else if (DECL_FUNCTION_VERSIONED (decl))
{
- name += ".default";
- return get_identifier (name.c_str());
- }
+ aarch64_fmv_feature_mask feature_mask
+ = get_feature_mask_for_version (decl);
- name += "._";
+ if (feature_mask == 0ULL)
+ return clone_identifier (id, "default");
- int num_features = ARRAY_SIZE (aarch64_fmv_feature_data);
- for (int i = 0; i < num_features; i++)
- {
- if (feature_mask & aarch64_fmv_feature_data[i].feature_mask)
- {
- name += "M";
- name += aarch64_fmv_feature_data[i].name;
- }
- }
+ std::string suffix = "_";
- if (DECL_ASSEMBLER_NAME_SET_P (decl))
- SET_DECL_RTL (decl, NULL);
+ int num_features = ARRAY_SIZE (aarch64_fmv_feature_data);
+ for (int i = 0; i < num_features; i++)
+ if (feature_mask & aarch64_fmv_feature_data[i].feature_mask)
+ {
+ suffix += "M";
+ suffix += aarch64_fmv_feature_data[i].name;
+ }
- id = get_identifier (name.c_str());
+ id = clone_identifier (id, suffix.c_str ());
+ }
}
return id;
}
@@ -20360,18 +20351,6 @@ aarch64_mangle_decl_assembler_name (tree decl, tree id)
This is computed by taking the default version's assembler name, and
stripping off the ".default" suffix if it's already been appended. */
-static tree
-get_suffixed_assembler_name (tree default_decl, const char *suffix)
-{
- std::string name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (default_decl));
-
- auto size = name.size ();
- if (size >= 8 && name.compare (size - 8, 8, ".default") == 0)
- name.resize (size - 8);
- name += suffix;
- return get_identifier (name.c_str());
-}
-
/* Make the resolver function decl to dispatch the versions of
a multi-versioned function, DEFAULT_DECL. IFUNC_ALIAS_DECL is
ifunc alias that will point to the created resolver. Create an
@@ -20385,11 +20364,6 @@ make_resolver_func (const tree default_decl,
{
tree decl, type, t;
- /* Create resolver function name based on default_decl. We need to remove an
- existing ".default" suffix if this has already been appended. */
- tree decl_name = get_suffixed_assembler_name (default_decl, ".resolver");
- const char *resolver_name = IDENTIFIER_POINTER (decl_name);
-
/* The resolver function should have signature
(void *) resolver (uint64_t, const __ifunc_arg_t *) */
type = build_function_type_list (ptr_type_node,
@@ -20397,10 +20371,21 @@ make_resolver_func (const tree default_decl,
build_ifunc_arg_type (),
NULL_TREE);
- decl = build_fn_decl (resolver_name, type);
- SET_DECL_ASSEMBLER_NAME (decl, decl_name);
+ cgraph_node *node = cgraph_node::get (default_decl);
+ gcc_assert (node && node->function_version ());
+
+ decl = build_fn_decl (IDENTIFIER_POINTER (DECL_NAME (default_decl)), type);
+
+ /* Set the assembler name to prevent cgraph_node attempting to mangle. */
+ SET_DECL_ASSEMBLER_NAME (decl, DECL_ASSEMBLER_NAME (default_decl));
+
+ cgraph_node *resolver_node = cgraph_node::get_create (decl);
+ resolver_node->dispatcher_resolver_function = true;
+
+ tree id = aarch64_mangle_decl_assembler_name
+ (decl, node->function_version ()->assembler_name);
+ symtab->change_decl_assembler_name (decl, id);
- DECL_NAME (decl) = decl_name;
TREE_USED (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
DECL_IGNORED_P (decl) = 1;
@@ -20465,7 +20450,7 @@ make_resolver_func (const tree default_decl,
gcc_assert (ifunc_alias_decl != NULL);
/* Mark ifunc_alias_decl as "ifunc" with resolver as resolver_name. */
DECL_ATTRIBUTES (ifunc_alias_decl)
- = make_attribute ("ifunc", resolver_name,
+ = make_attribute ("ifunc", IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
DECL_ATTRIBUTES (ifunc_alias_decl));
/* Create the alias for dispatch to resolver here. */
@@ -20742,27 +20727,6 @@ aarch64_generate_version_dispatcher_body (void *node_p)
cgraph_edge::rebuild_edges ();
pop_cfun ();
- /* Fix up symbol names. First we need to obtain the base name, which may
- have already been mangled. */
- tree base_name = get_suffixed_assembler_name (default_ver_decl, "");
-
- /* We need to redo the version mangling on the non-default versions for the
- target_clones case. Redoing the mangling for the target_version case is
- redundant but does no harm. We need to skip the default version, because
- expand_clones will append ".default" later; fortunately that suffix is the
- one we want anyway. */
- for (versn_info = node_version_info->next->next; versn_info;
- versn_info = versn_info->next)
- {
- tree version_decl = versn_info->this_node->decl;
- tree name = aarch64_mangle_decl_assembler_name (version_decl,
- base_name);
- symtab->change_decl_assembler_name (version_decl, name);
- }
-
- /* We also need to use the base name for the ifunc declaration. */
- symtab->change_decl_assembler_name (node->decl, base_name);
-
return resolver_decl;
}
@@ -20806,20 +20770,9 @@ aarch64_get_function_versions_dispatcher (void *decl)
if (targetm.has_ifunc_p ())
{
struct cgraph_function_version_info *it_v = NULL;
- struct cgraph_node *dispatcher_node = NULL;
- struct cgraph_function_version_info *dispatcher_version_info = NULL;
/* Right now, the dispatching is done via ifunc. */
dispatch_decl = make_dispatcher_decl (default_node->decl);
- TREE_NOTHROW (dispatch_decl) = TREE_NOTHROW (fn);
-
- dispatcher_node = cgraph_node::get_create (dispatch_decl);
- gcc_assert (dispatcher_node != NULL);
- dispatcher_node->dispatcher_function = 1;
- dispatcher_version_info
- = dispatcher_node->insert_new_function_version ();
- dispatcher_version_info->next = default_version_info;
- dispatcher_node->definition = 1;
/* Set the dispatcher for all the versions. */
it_v = default_version_info;
@@ -3888,6 +3888,37 @@ dispatch_function_versions (tree dispatch_decl,
return 0;
}
+/* Return true if symbol is valid in assembler name. */
+
+static bool
+is_valid_asm_symbol (char c)
+{
+ if ('a' <= c && c <= 'z')
+ return true;
+ if ('A' <= c && c <= 'Z')
+ return true;
+ if ('0' <= c && c <= '9')
+ return true;
+ if (c == '_')
+ return true;
+ return false;
+}
+
+/* Replace all not valid assembler symbols with '_'. */
+static void
+create_new_asm_name (char *old_asm_name, char *new_asm_name)
+{
+ int i;
+ int old_name_len = strlen (old_asm_name);
+ /* Replace all not valid assembler symbols with '_'. */
+ for (i = 0; i < old_name_len; i++)
+ if (!is_valid_asm_symbol (old_asm_name[i]))
+ new_asm_name[i] = '_';
+ else
+ new_asm_name[i] = old_asm_name[i];
+ new_asm_name[old_name_len] = '\0';
+}
+
/* 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. */
@@ -3896,8 +3927,7 @@ static tree
ix86_mangle_function_version_assembler_name (tree decl, tree id)
{
tree version_attr;
- const char *orig_name, *version_string;
- char *attr_str, *assembler_name;
+ char *attr_str;
if (DECL_DECLARED_INLINE_P (decl)
&& lookup_attribute ("gnu_inline",
@@ -3915,25 +3945,24 @@ ix86_mangle_function_version_assembler_name (tree decl, tree id)
/* target attribute string cannot be NULL. */
gcc_assert (version_attr != NULL_TREE);
- orig_name = IDENTIFIER_POINTER (id);
- version_string
- = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (version_attr)));
-
- if (strcmp (version_string, "default") == 0)
+ cgraph_node *node = cgraph_node::get (decl);
+ if (!node && node->is_target_clone && is_function_default_version (decl))
return id;
attr_str = sorted_attr_string (TREE_VALUE (version_attr));
- assembler_name = XNEWVEC (char, strlen (orig_name) + strlen (attr_str) + 2);
- sprintf (assembler_name, "%s.%s", orig_name, attr_str);
+ char *suffix = XNEWVEC (char, strlen (attr_str) + 1);
+ create_new_asm_name (attr_str, suffix);
/* Allow assembler name to be modified if already set. */
if (DECL_ASSEMBLER_NAME_SET_P (decl))
SET_DECL_RTL (decl, NULL);
- tree ret = get_identifier (assembler_name);
+ tree ret = clone_identifier (id, suffix);
+
XDELETEVEC (attr_str);
- XDELETEVEC (assembler_name);
+ XDELETEVEC (suffix);
+
return ret;
}
@@ -3941,9 +3970,21 @@ tree
ix86_mangle_decl_assembler_name (tree decl, tree id)
{
/* For function version, add the target suffix to the assembler name. */
- if (TREE_CODE (decl) == FUNCTION_DECL
- && DECL_FUNCTION_VERSIONED (decl))
- id = ix86_mangle_function_version_assembler_name (decl, id);
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ cgraph_node *node = cgraph_node::get (decl);
+ /* Mangle all versions when annotated with target_clones, but only
+ non-default versions when annotated with target attributes. */
+ if (DECL_FUNCTION_VERSIONED (decl)
+ && (node->is_target_clone
+ || !is_function_default_version (node->decl)))
+ id = ix86_mangle_function_version_assembler_name (decl, id);
+ /* Mangle the dispatched symbol but only in the case of target clones. */
+ else if (node && node->dispatcher_function && !node->is_target_clone)
+ id = clone_identifier (id, "ifunc");
+ else if (node && node->dispatcher_resolver_function)
+ id = clone_identifier (id, "resolver");
+ }
#ifdef SUBTARGET_MANGLE_DECL_ASSEMBLER_NAME
id = SUBTARGET_MANGLE_DECL_ASSEMBLER_NAME (decl, id);
#endif
@@ -3982,6 +4023,7 @@ ix86_get_function_versions_dispatcher (void *decl)
default_version_info = node_v;
while (default_version_info->prev != NULL)
default_version_info = default_version_info->prev;
+ default_node = default_version_info->this_node;
/* If there is no default node, just return NULL. */
if (!is_function_default_version (default_node->decl))
@@ -3991,20 +4033,9 @@ ix86_get_function_versions_dispatcher (void *decl)
if (targetm.has_ifunc_p ())
{
struct cgraph_function_version_info *it_v = NULL;
- struct cgraph_node *dispatcher_node = NULL;
- struct cgraph_function_version_info *dispatcher_version_info = NULL;
/* Right now, the dispatching is done via ifunc. */
dispatch_decl = make_dispatcher_decl (default_node->decl);
- TREE_NOTHROW (dispatch_decl) = TREE_NOTHROW (fn);
-
- dispatcher_node = cgraph_node::get_create (dispatch_decl);
- gcc_assert (dispatcher_node != NULL);
- dispatcher_node->dispatcher_function = 1;
- dispatcher_version_info
- = dispatcher_node->insert_new_function_version ();
- dispatcher_version_info->next = default_version_info;
- dispatcher_node->definition = 1;
/* Set the dispatcher for all the versions. */
it_v = default_version_info;
@@ -4038,17 +4069,28 @@ make_resolver_func (const tree default_decl,
{
tree decl, type, t;
- /* Create resolver function name based on default_decl. */
- tree decl_name = clone_function_name (default_decl, "resolver");
- const char *resolver_name = IDENTIFIER_POINTER (decl_name);
-
/* The resolver function should return a (void *). */
type = build_function_type_list (ptr_type_node, NULL_TREE);
- decl = build_fn_decl (resolver_name, type);
- SET_DECL_ASSEMBLER_NAME (decl, decl_name);
+ cgraph_node *node = cgraph_node::get (default_decl);
+ gcc_assert (node && node->function_version ());
+
+ decl = build_fn_decl (IDENTIFIER_POINTER (DECL_NAME (default_decl)), type);
+
+ /* Set the assembler name to prevent cgraph_node attempting to mangle. */
+ SET_DECL_ASSEMBLER_NAME (decl, DECL_ASSEMBLER_NAME (default_decl));
+
+ cgraph_node *resolver_node = cgraph_node::get_create (decl);
+ resolver_node->dispatcher_resolver_function = true;
+
+ if (node->is_target_clone)
+ resolver_node->is_target_clone = true;
+
+ tree id = ix86_mangle_decl_assembler_name
+ (decl, node->function_version ()->assembler_name);
+ SET_DECL_ASSEMBLER_NAME (decl, id);
- DECL_NAME (decl) = decl_name;
+ DECL_NAME (decl) = DECL_NAME (default_decl);
TREE_USED (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
DECL_IGNORED_P (decl) = 1;
@@ -4095,7 +4137,7 @@ make_resolver_func (const tree default_decl,
gcc_assert (ifunc_alias_decl != NULL);
/* Mark ifunc_alias_decl as "ifunc" with resolver as resolver_name. */
DECL_ATTRIBUTES (ifunc_alias_decl)
- = make_attribute ("ifunc", resolver_name,
+ = make_attribute ("ifunc", IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
DECL_ATTRIBUTES (ifunc_alias_decl));
/* Create the alias for dispatch to resolver here. */
@@ -13220,32 +13220,31 @@ tree
riscv_mangle_decl_assembler_name (tree decl, tree id)
{
/* For function version, add the target suffix to the assembler name. */
- if (TREE_CODE (decl) == FUNCTION_DECL
- && DECL_FUNCTION_VERSIONED (decl))
+ if (TREE_CODE (decl) == FUNCTION_DECL)
{
- std::string name = IDENTIFIER_POINTER (id) + std::string (".");
- tree target_attr = lookup_attribute ("target_version",
- DECL_ATTRIBUTES (decl));
-
- if (target_attr == NULL_TREE)
+ cgraph_node *node = cgraph_node::get (decl);
+ if (node && node->dispatcher_resolver_function)
+ return clone_identifier (id, "resolver");
+ else if (DECL_FUNCTION_VERSIONED (decl))
{
- name += "default";
- return get_identifier (name.c_str ());
- }
+ tree target_attr
+ = lookup_attribute ("target_version", DECL_ATTRIBUTES (decl));
- const char *version_string = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE
- (target_attr)));
+ if (target_attr == NULL_TREE)
+ return clone_identifier (id, "default");
- /* Replace non-alphanumeric characters with underscores as the suffix. */
- for (const char *c = version_string; *c; c++)
- name += ISALNUM (*c) == 0 ? '_' : *c;
+ const char *version_string
+ = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (target_attr)));
- if (DECL_ASSEMBLER_NAME_SET_P (decl))
- SET_DECL_RTL (decl, NULL);
+ /* Replace non-alphanumeric characters with underscores as the suffix.
+ */
+ std::string suffix = "";
+ for (const char *c = version_string; *c; c++)
+ suffix += ISALNUM (*c) == 0 ? '_' : *c;
- id = get_identifier (name.c_str ());
+ id = clone_identifier (id, suffix.c_str ());
+ }
}
-
return id;
}
@@ -13526,22 +13525,6 @@ dispatch_function_versions (tree dispatch_decl,
return 0;
}
-/* Return an identifier for the base assembler name of a versioned function.
- This is computed by taking the default version's assembler name, and
- stripping off the ".default" suffix if it's already been appended. */
-
-static tree
-get_suffixed_assembler_name (tree default_decl, const char *suffix)
-{
- std::string name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (default_decl));
-
- auto size = name.size ();
- if (size >= 8 && name.compare (size - 8, 8, ".default") == 0)
- name.resize (size - 8);
- name += suffix;
- return get_identifier (name.c_str ());
-}
-
/* Make the resolver function decl to dispatch the versions of
a multi-versioned function, DEFAULT_DECL. IFUNC_ALIAS_DECL is
ifunc alias that will point to the created resolver. Create an
@@ -13555,10 +13538,8 @@ make_resolver_func (const tree default_decl,
{
tree decl, type, t;
- /* Create resolver function name based on default_decl. We need to remove an
- existing ".default" suffix if this has already been appended. */
- tree decl_name = get_suffixed_assembler_name (default_decl, ".resolver");
- const char *resolver_name = IDENTIFIER_POINTER (decl_name);
+ cgraph_node *node = cgraph_node::get (default_decl);
+ gcc_assert (node && node->function_version ());
/* The resolver function should have signature
(void *) resolver (uint64_t, void *) */
@@ -13567,10 +13548,21 @@ make_resolver_func (const tree default_decl,
ptr_type_node,
NULL_TREE);
- decl = build_fn_decl (resolver_name, type);
- SET_DECL_ASSEMBLER_NAME (decl, decl_name);
+ decl = build_fn_decl (IDENTIFIER_POINTER (DECL_NAME (default_decl)), type);
+
+ /* Set the assembler name to prevent cgraph_node attempting to mangle. */
+ SET_DECL_ASSEMBLER_NAME (decl, DECL_ASSEMBLER_NAME (default_decl));
+
+ cgraph_node *resolver_node = cgraph_node::get_create (decl);
+ resolver_node->dispatcher_resolver_function = true;
+
+ if (node->is_target_clone)
+ resolver_node->is_target_clone = true;
+
+ tree id = riscv_mangle_decl_assembler_name
+ (decl, node->function_version ()->assembler_name);
+ symtab->change_decl_assembler_name (decl, id);
- DECL_NAME (decl) = decl_name;
TREE_USED (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
DECL_IGNORED_P (decl) = 1;
@@ -13635,7 +13627,7 @@ make_resolver_func (const tree default_decl,
gcc_assert (ifunc_alias_decl != NULL);
/* Mark ifunc_alias_decl as "ifunc" with resolver as resolver_name. */
DECL_ATTRIBUTES (ifunc_alias_decl)
- = make_attribute ("ifunc", resolver_name,
+ = make_attribute ("ifunc", IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
DECL_ATTRIBUTES (ifunc_alias_decl));
/* Create the alias for dispatch to resolver here. */
@@ -13700,27 +13692,6 @@ riscv_generate_version_dispatcher_body (void *node_p)
cgraph_edge::rebuild_edges ();
pop_cfun ();
- /* Fix up symbol names. First we need to obtain the base name, which may
- have already been mangled. */
- tree base_name = get_suffixed_assembler_name (default_ver_decl, "");
-
- /* We need to redo the version mangling on the non-default versions for the
- target_clones case. Redoing the mangling for the target_version case is
- redundant but does no harm. We need to skip the default version, because
- expand_clones will append ".default" later; fortunately that suffix is the
- one we want anyway. */
- for (versn_info = node_version_info->next->next; versn_info;
- versn_info = versn_info->next)
- {
- tree version_decl = versn_info->this_node->decl;
- tree name = riscv_mangle_decl_assembler_name (version_decl,
- base_name);
- symtab->change_decl_assembler_name (version_decl, name);
- }
-
- /* We also need to use the base name for the ifunc declaration. */
- symtab->change_decl_assembler_name (node->decl, base_name);
-
return resolver_decl;
}
@@ -13764,20 +13735,9 @@ riscv_get_function_versions_dispatcher (void *decl)
if (targetm.has_ifunc_p ())
{
struct cgraph_function_version_info *it_v = NULL;
- struct cgraph_node *dispatcher_node = NULL;
- struct cgraph_function_version_info *dispatcher_version_info = NULL;
/* Right now, the dispatching is done via ifunc. */
dispatch_decl = make_dispatcher_decl (default_node->decl);
- TREE_NOTHROW (dispatch_decl) = TREE_NOTHROW (fn);
-
- dispatcher_node = cgraph_node::get_create (dispatch_decl);
- gcc_assert (dispatcher_node != NULL);
- dispatcher_node->dispatcher_function = 1;
- dispatcher_version_info
- = dispatcher_node->insert_new_function_version ();
- dispatcher_version_info->next = default_version_info;
- dispatcher_node->definition = 1;
/* Set the dispatcher for all the versions. */
it_v = default_version_info;
@@ -88,6 +88,7 @@
extern tree rs6000_builtin_mask_for_load (void);
extern tree rs6000_builtin_md_vectorized_function (tree, tree, tree);
extern tree rs6000_builtin_reciprocal (tree);
+static tree rs6000_mangle_decl_assembler_name (tree, tree);
/* Set -mabi=ieeelongdouble on some old targets. In the future, power server
systems will also set long double to be IEEE 128-bit. AIX and Darwin
@@ -25352,20 +25353,9 @@ rs6000_get_function_versions_dispatcher (void *decl)
if (targetm.has_ifunc_p ())
{
struct cgraph_function_version_info *it_v = NULL;
- struct cgraph_node *dispatcher_node = NULL;
- struct cgraph_function_version_info *dispatcher_version_info = NULL;
/* Right now, the dispatching is done via ifunc. */
dispatch_decl = make_dispatcher_decl (default_node->decl);
- TREE_NOTHROW (dispatch_decl) = TREE_NOTHROW (fn);
-
- dispatcher_node = cgraph_node::get_create (dispatch_decl);
- gcc_assert (dispatcher_node != NULL);
- dispatcher_node->dispatcher_function = 1;
- dispatcher_version_info
- = dispatcher_node->insert_new_function_version ();
- dispatcher_version_info->next = default_version_info;
- dispatcher_node->definition = 1;
/* Set the dispatcher for all the versions. */
it_v = default_version_info;
@@ -25398,13 +25388,24 @@ make_resolver_func (const tree default_decl,
{
/* Make the resolver function static. The resolver function returns
void *. */
- tree decl_name = clone_function_name (default_decl, "resolver");
- const char *resolver_name = IDENTIFIER_POINTER (decl_name);
tree type = build_function_type_list (ptr_type_node, NULL_TREE);
- tree decl = build_fn_decl (resolver_name, type);
- SET_DECL_ASSEMBLER_NAME (decl, decl_name);
+ tree decl = build_fn_decl (IDENTIFIER_POINTER (DECL_NAME (default_decl)),
+ type);
+
+ cgraph_node *node = cgraph_node::get (default_decl);
+ gcc_assert (node && node->function_version ());
+
+ /* Set the assembler name to prevent cgraph_node attempting to mangle. */
+ SET_DECL_ASSEMBLER_NAME (decl, DECL_ASSEMBLER_NAME (default_decl));
+
+ cgraph_node *resolver_node = cgraph_node::get_create (decl);
+ resolver_node->dispatcher_resolver_function = true;
+
+ tree id = rs6000_mangle_decl_assembler_name
+ (decl, node->function_version ()->assembler_name);
+ symtab->change_decl_assembler_name (decl, id);
- DECL_NAME (decl) = decl_name;
+ DECL_NAME (decl) = DECL_NAME (default_decl);
TREE_USED (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
DECL_IGNORED_P (decl) = 0;
@@ -25450,7 +25451,8 @@ make_resolver_func (const tree default_decl,
/* Mark dispatch_decl as "ifunc" with resolver as resolver_name. */
DECL_ATTRIBUTES (dispatch_decl)
- = make_attribute ("ifunc", resolver_name, DECL_ATTRIBUTES (dispatch_decl));
+ = make_attribute ("ifunc", IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
+ DECL_ATTRIBUTES (dispatch_decl));
cgraph_node::create_same_body_alias (dispatch_decl, decl);
@@ -28490,6 +28492,77 @@ complex_divide_builtin_code (machine_mode mode)
return (built_in_function) func;
}
+static bool
+is_valid_asm_symbol (char c)
+{
+ if ('a' <= c && c <= 'z')
+ return true;
+ if ('A' <= c && c <= 'Z')
+ return true;
+ if ('0' <= c && c <= '9')
+ return true;
+ if (c == '_')
+ return true;
+ return false;
+}
+
+/* Replace all not valid assembler symbols with '_'. */
+static void
+create_new_asm_name (char *old_asm_name, char *new_asm_name)
+{
+ int i;
+ int old_name_len = strlen (old_asm_name);
+ /* Replace all not valid assembler symbols with '_'. */
+ for (i = 0; i < old_name_len; i++)
+ if (!is_valid_asm_symbol (old_asm_name[i]))
+ new_asm_name[i] = '_';
+ else
+ new_asm_name[i] = old_asm_name[i];
+ new_asm_name[old_name_len] = '\0';
+}
+
+/* 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. */
+
+static tree
+rs6000_mangle_function_version_assembler_name (tree decl, tree id)
+{
+ tree version_attr;
+ const char *version_string;
+ char *attr_str;
+
+ if (DECL_DECLARED_INLINE_P (decl)
+ && lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (decl)))
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "function versions cannot be marked as %<gnu_inline%>,"
+ " bodies have to be generated");
+
+ if (DECL_VIRTUAL_P (decl) || DECL_VINDEX (decl))
+ sorry ("virtual function multiversioning not supported");
+
+ version_attr = lookup_attribute ("target", DECL_ATTRIBUTES (decl));
+
+ /* target attribute string cannot be NULL. */
+ gcc_assert (version_attr != NULL_TREE);
+
+ version_string = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (version_attr)));
+
+ if (strcmp (version_string, "default") == 0)
+ return clone_identifier (id, "default");
+
+ attr_str = sorted_attr_string (TREE_VALUE (version_attr));
+
+ char *suffix = XNEWVEC (char, strlen (attr_str) + 1);
+ create_new_asm_name (attr_str, suffix);
+
+ tree ret = clone_identifier (id, suffix);
+
+ XDELETEVEC (attr_str);
+ XDELETEVEC (suffix);
+ return ret;
+}
+
/* On 64-bit Linux and Freebsd systems, possibly switch the long double library
function names from <foo>l to <foo>f128 if the default long double type is
IEEE 128-bit. Typically, with the C and C++ languages, the standard math.h
@@ -28675,6 +28748,14 @@ rs6000_mangle_decl_assembler_name (tree decl, tree id)
}
}
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ cgraph_node *node = cgraph_node::get (decl);
+ if (node && node->dispatcher_resolver_function)
+ id = clone_identifier (id, "resolver");
+ else if (DECL_FUNCTION_VERSIONED (decl))
+ id = rs6000_mangle_function_version_assembler_name (decl, id);
+ }
return id;
}
@@ -1274,6 +1274,13 @@ maybe_mark_function_versioned (tree decl)
{
if (!DECL_FUNCTION_VERSIONED (decl))
{
+ /* We need to insert function version now to make sure the correct
+ pre-mangled assembler name is recorded. */
+ cgraph_node *node = cgraph_node::get_create (decl);
+
+ if (!node->function_version ())
+ node->insert_new_function_version ();
+
DECL_FUNCTION_VERSIONED (decl) = 1;
/* If DECL_ASSEMBLER_NAME has already been set, re-mangle
to include the version marker. */
@@ -166,9 +166,6 @@ create_dispatcher_calls (struct cgraph_node *node)
}
}
- tree fname = clone_function_name (node->decl, "default");
- symtab->change_decl_assembler_name (node->decl, fname);
-
if (node->definition)
{
/* FIXME: copy of cgraph_node::make_local that should be cleaned up
@@ -184,100 +181,6 @@ create_dispatcher_calls (struct cgraph_node *node)
}
}
-/* Create string with attributes separated by TARGET_CLONES_ATTR_SEPARATOR.
- Return number of attributes. */
-
-static int
-get_attr_str (tree arglist, char *attr_str)
-{
- tree arg;
- size_t str_len_sum = 0;
- int argnum = 0;
-
- for (arg = arglist; arg; arg = TREE_CHAIN (arg))
- {
- const char *str = TREE_STRING_POINTER (TREE_VALUE (arg));
- size_t len = strlen (str);
- for (const char *p = strchr (str, TARGET_CLONES_ATTR_SEPARATOR);
- p;
- p = strchr (p + 1, TARGET_CLONES_ATTR_SEPARATOR))
- argnum++;
- memcpy (attr_str + str_len_sum, str, len);
- attr_str[str_len_sum + len]
- = TREE_CHAIN (arg) ? TARGET_CLONES_ATTR_SEPARATOR : '\0';
- str_len_sum += len + 1;
- argnum++;
- }
- return argnum;
-}
-
-/* Return number of attributes separated by TARGET_CLONES_ATTR_SEPARATOR
- and put them into ARGS.
- If there is no DEFAULT attribute return -1.
- If there is an empty string in attribute return -2.
- If there are multiple DEFAULT attributes return -3.
- */
-
-static int
-separate_attrs (char *attr_str, char **attrs, int attrnum)
-{
- int i = 0;
- int default_count = 0;
- static const char separator_str[] = { TARGET_CLONES_ATTR_SEPARATOR, 0 };
-
- for (char *attr = strtok (attr_str, separator_str);
- attr != NULL; attr = strtok (NULL, separator_str))
- {
- if (strcmp (attr, "default") == 0)
- {
- default_count++;
- continue;
- }
- attrs[i++] = attr;
- }
- if (default_count == 0)
- return -1;
- else if (default_count > 1)
- return -3;
- else if (i + default_count < attrnum)
- return -2;
-
- return i;
-}
-
-/* Return true if symbol is valid in assembler name. */
-
-static bool
-is_valid_asm_symbol (char c)
-{
- if ('a' <= c && c <= 'z')
- return true;
- if ('A' <= c && c <= 'Z')
- return true;
- if ('0' <= c && c <= '9')
- return true;
- if (c == '_')
- return true;
- return false;
-}
-
-/* Replace all not valid assembler symbols with '_'. */
-
-static void
-create_new_asm_name (char *old_asm_name, char *new_asm_name)
-{
- int i;
- int old_name_len = strlen (old_asm_name);
-
- /* Replace all not valid assembler symbols with '_'. */
- for (i = 0; i < old_name_len; i++)
- if (!is_valid_asm_symbol (old_asm_name[i]))
- new_asm_name[i] = '_';
- else
- new_asm_name[i] = old_asm_name[i];
- new_asm_name[old_name_len] = '\0';
-}
-
/* Creates target clone of NODE. */
static cgraph_node *
@@ -313,7 +216,6 @@ create_target_clone (cgraph_node *node, bool definition, char *name,
static bool
expand_target_clones (struct cgraph_node *node, bool definition)
{
- int i;
/* Parsing target attributes separated by TARGET_CLONES_ATTR_SEPARATOR. */
tree attr_target = lookup_attribute ("target_clones",
DECL_ATTRIBUTES (node->decl));
@@ -321,11 +223,12 @@ expand_target_clones (struct cgraph_node *node, bool definition)
if (!attr_target)
return false;
- tree arglist = TREE_VALUE (attr_target);
- int attr_len = get_target_clone_attr_len (arglist);
+ int num_defaults = 0;
+ auto_vec<string_slice> attr_list = get_clone_versions (node->decl,
+ &num_defaults);
/* No need to clone for 1 target attribute. */
- if (attr_len == -1)
+ if (attr_list.length () == 1)
{
warning_at (DECL_SOURCE_LOCATION (node->decl),
0, "single %<target_clones%> attribute is ignored");
@@ -352,95 +255,114 @@ expand_target_clones (struct cgraph_node *node, bool definition)
return false;
}
- char *attr_str = XNEWVEC (char, attr_len);
- int attrnum = get_attr_str (arglist, attr_str);
- char **attrs = XNEWVEC (char *, attrnum);
-
- attrnum = separate_attrs (attr_str, attrs, attrnum);
- switch (attrnum)
+ /* Disallow multiple defaults. */
+ if (num_defaults > 1)
{
- case -1:
- error_at (DECL_SOURCE_LOCATION (node->decl),
- "%<default%> target was not set");
- break;
- case -2:
- error_at (DECL_SOURCE_LOCATION (node->decl),
- "an empty string cannot be in %<target_clones%> attribute");
- break;
- case -3:
error_at (DECL_SOURCE_LOCATION (node->decl),
"multiple %<default%> targets were set");
- break;
- default:
- break;
+ return false;
}
-
- if (attrnum < 0)
+ /* Disallow target clones with no defaults. */
+ if (num_defaults == 0)
{
- XDELETEVEC (attrs);
- XDELETEVEC (attr_str);
+ error_at (DECL_SOURCE_LOCATION (node->decl),
+ "%<default%> target was not set");
return false;
}
- const char *new_attr_name = (TARGET_HAS_FMV_TARGET_ATTRIBUTE
- ? "target" : "target_version");
- cgraph_function_version_info *decl1_v = NULL;
- cgraph_function_version_info *decl2_v = NULL;
- cgraph_function_version_info *before = NULL;
- cgraph_function_version_info *after = NULL;
- decl1_v = node->function_version ();
- if (decl1_v == NULL)
- decl1_v = node->insert_new_function_version ();
- before = decl1_v;
- DECL_FUNCTION_VERSIONED (node->decl) = 1;
-
- for (i = 0; i < attrnum; i++)
+ /* Disallow any empty values in the clone attr. */
+ for (string_slice attr : attr_list)
+ if (attr.empty () || !attr.is_valid ())
+ {
+ error_at (DECL_SOURCE_LOCATION (node->decl),
+ "an empty string cannot be in %<target_clones%> attribute");
+ return false;
+ }
+
+ string_slice new_attr_name = TARGET_HAS_FMV_TARGET_ATTRIBUTE
+ ? "target"
+ : "target_version";
+
+ cgraph_function_version_info *node_v = node->function_version ();
+
+ if (!node_v)
+ node_v = node->insert_new_function_version ();
+
+ /* If this target_clones contains a default, then convert this node to the
+ default. If this node does not contain default (this is only possible
+ in target_version semantics) then remove the node. This is safe at the
+ point as only target_clones declarations containing default version is
+ resolvable so this decl will have no calls/refrences. */
+
+ tree attrs = remove_attribute ("target_clones",
+ DECL_ATTRIBUTES (node->decl));
+ tree assembler_name = node_v->assembler_name;
+
+ /* Change the current node into the default node. */
+ if (num_defaults == 1)
{
- char *attr = attrs[i];
+ /* Setting new attribute to initial function. */
+ tree attributes = make_attribute (new_attr_name, "default", attrs);
+ DECL_ATTRIBUTES (node->decl) = attributes;
+ DECL_FUNCTION_VERSIONED (node->decl) = true;
+
+ node->is_target_clone = true;
+ node->local = false;
+
+ /* Remangle base node after new target version string set. */
+ tree id = targetm.mangle_decl_assembler_name (node->decl, assembler_name);
+ symtab->change_decl_assembler_name (node->decl, id);
+ }
+ else
+ {
+ /* Target clones without a default are only allowed for target_version
+ semantics where we can have target_clones/target_version mixing. */
+ gcc_assert (!TARGET_HAS_FMV_TARGET_ATTRIBUTE);
+
+ /* If there isn't a default version, can safely remove this version.
+ The node itself gets removed after the other versions are created. */
+ cgraph_function_version_info *temp = node_v;
+ node_v = node_v->next ? node_v->next : node_v->prev;
+ cgraph_node::delete_function_version (temp);
+ }
+
+ for (string_slice attr : attr_list)
+ {
+ /* Skip default nodes. */
+ if (attr == "default")
+ continue;
/* Create new target clone. */
tree attributes = make_attribute (new_attr_name, attr,
DECL_ATTRIBUTES (node->decl));
- char *suffix = XNEWVEC (char, strlen (attr) + 1);
- create_new_asm_name (attr, suffix);
- cgraph_node *new_node = create_target_clone (node, definition, suffix,
- attributes);
- XDELETEVEC (suffix);
+ cgraph_node *new_node
+ = create_target_clone (node, definition, NULL, attributes);
if (new_node == NULL)
- {
- XDELETEVEC (attrs);
- XDELETEVEC (attr_str);
- return false;
- }
+ return false;
new_node->local = false;
- decl2_v = new_node->function_version ();
- if (decl2_v != NULL)
- continue;
- decl2_v = new_node->insert_new_function_version ();
-
- /* Chain decl2_v and decl1_v. All semantically identical versions
- will be chained together. */
- after = decl2_v;
- while (before->next != NULL)
- before = before->next;
- while (after->prev != NULL)
- after = after->prev;
-
- before->next = after;
- after->prev = before;
- DECL_FUNCTION_VERSIONED (new_node->decl) = 1;
+ DECL_FUNCTION_VERSIONED (new_node->decl) = true;
+ if (!node_v)
+ node_v = new_node->insert_new_function_version ();
+ else
+ cgraph_node::add_function_version (node_v, new_node->decl);
+
+ /* Use the base nodes assembler name for all created nodes. */
+ new_node->function_version ()->assembler_name = assembler_name;
+ new_node->is_target_clone = true;
+
+ /* Mangle all new nodes. */
+ tree id = targetm.mangle_decl_assembler_name
+ (new_node->decl, new_node->function_version ()->assembler_name);
+ symtab->change_decl_assembler_name (new_node->decl, id);
}
- XDELETEVEC (attrs);
- XDELETEVEC (attr_str);
+ /* If there are no default versions in the target_clones, this node is not
+ reused, so can delete this node. */
+ if (num_defaults == 0)
+ node->remove ();
- /* Setting new attribute to initial function. */
- tree attributes = make_attribute (new_attr_name, "default",
- DECL_ATTRIBUTES (node->decl));
- DECL_ATTRIBUTES (node->decl) = attributes;
- node->local = false;
return true;
}
@@ -55,14 +55,14 @@ int bar(int x)
/* { dg-final { scan-assembler-times "\n_Z3foov\.arch_slm:\n" 1 } } */
/* { dg-final { scan-assembler-times "\n_Z3foov\.sse4.2:\n" 1 } } */
/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\tcall\t_Z7_Z3foovv\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\t\.type\t_Z7_Z3foovv, @gnu_indirect_function\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\t\.set\t_Z7_Z3foovv,_Z3foov\.resolver\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tcall\t_Z3foov.ifunc\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3foov.ifunc, @gnu_indirect_function\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov.ifunc,_Z3foov\.resolver\n" 1 } } */
/* { dg-final { scan-assembler-times "\n_Z3fooi:\n" 1 } } */
/* { dg-final { scan-assembler-times "\n_Z3fooi\.arch_slm:\n" 1 } } */
/* { dg-final { scan-assembler-times "\n_Z3fooi\.sse4.2:\n" 1 } } */
/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\tcall\t_Z7_Z3fooii\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\t\.type\t_Z7_Z3fooii, @gnu_indirect_function\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\t\.set\t_Z7_Z3fooii,_Z3fooi\.resolver\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tcall\t_Z3fooi.ifunc\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi.ifunc, @gnu_indirect_function\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi.ifunc,_Z3fooi\.resolver\n" 1 } } */
@@ -32,13 +32,13 @@ int bar()
/* { dg-final { scan-assembler-times "\n_Z3foov\.arch_slm:\n" 0 } } */
/* { dg-final { scan-assembler-times "\n_Z3foov\.sse4.2:\n" 0 } } */
/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\tcall\t_Z7_Z3foovv\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\t\.type\t_Z7_Z3foovv, @gnu_indirect_function\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\t\.set\t_Z7_Z3foovv,_Z3foov\.resolver\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tcall\t_Z3foov.ifunc\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3foov.ifunc, @gnu_indirect_function\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov.ifunc,_Z3foov\.resolver\n" 1 } } */
/* { dg-final { scan-assembler-times "\n_Z3fooi:\n" 0 } } */
/* { dg-final { scan-assembler-times "\n_Z3fooi\.arch_slm:\n" 0 } } */
/* { dg-final { scan-assembler-times "\n_Z3fooi\.sse4.2:\n" 0 } } */
/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n\t\.type\t_Z7_Z3fooii, @gnu_indirect_function\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n\t\.set\t_Z7_Z3fooii,_Z3fooi\.resolver\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi.ifunc, @gnu_indirect_function\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi.ifunc,_Z3fooi\.resolver\n" 0 } } */
@@ -38,13 +38,13 @@ int bar()
/* { dg-final { scan-assembler-times "\n_Z3foov\.arch_slm:\n" 0 } } */
/* { dg-final { scan-assembler-times "\n_Z3foov\.sse4.2:\n" 0 } } */
/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\tcall\t_Z7_Z3foovv\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\t\.type\t_Z7_Z3foovv, @gnu_indirect_function\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\t\.set\t_Z7_Z3foovv,_Z3foov\.resolver\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tcall\t_Z3foov.ifunc\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3foov.ifunc, @gnu_indirect_function\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov.ifunc,_Z3foov\.resolver\n" 1 } } */
/* { dg-final { scan-assembler-times "\n_Z3fooi:\n" 1 } } */
/* { dg-final { scan-assembler-times "\n_Z3fooi\.arch_slm:\n" 0 } } */
/* { dg-final { scan-assembler-times "\n_Z3fooi\.sse4.2:\n" 0 } } */
/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n\t\.type\t_Z7_Z3fooii, @gnu_indirect_function\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n\t\.set\t_Z7_Z3fooii,_Z3fooi\.resolver\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi.ifunc, @gnu_indirect_function\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi.ifunc,_Z3fooi\.resolver\n" 0 } } */
@@ -44,13 +44,13 @@ int bar()
/* { dg-final { scan-assembler-times "\n_Z3foov\.arch_slm:\n" 1 } } */
/* { dg-final { scan-assembler-times "\n_Z3foov\.sse4.2:\n" 1 } } */
/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\tcall\t_Z7_Z3foovv\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\t\.type\t_Z7_Z3foovv, @gnu_indirect_function\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\t\.set\t_Z7_Z3foovv,_Z3foov\.resolver\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tcall\t_Z3foov.ifunc\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3foov.ifunc, @gnu_indirect_function\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov.ifunc,_Z3foov\.resolver\n" 1 } } */
/* { dg-final { scan-assembler-times "\n_Z3fooi:\n" 0 } } */
/* { dg-final { scan-assembler-times "\n_Z3fooi\.arch_slm:\n" 1 } } */
/* { dg-final { scan-assembler-times "\n_Z3fooi\.sse4.2:\n" 1 } } */
/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n\t\.type\t_Z7_Z3fooii, @gnu_indirect_function\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n\t\.set\t_Z7_Z3fooii,_Z3fooi\.resolver\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi.ifunc, @gnu_indirect_function\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi.ifunc,_Z3fooi\.resolver\n" 0 } } */
@@ -15346,32 +15346,6 @@ get_attr_nonstring_decl (tree expr, tree *ref)
return NULL_TREE;
}
-/* Return length of attribute names string,
- if arglist chain > 1, -1 otherwise. */
-
-int
-get_target_clone_attr_len (tree arglist)
-{
- tree arg;
- int str_len_sum = 0;
- int argnum = 0;
-
- 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;
- for (const char *p = strchr (str, TARGET_CLONES_ATTR_SEPARATOR);
- p;
- p = strchr (p + 1, TARGET_CLONES_ATTR_SEPARATOR))
- argnum++;
- argnum++;
- }
- if (argnum <= 1)
- return -1;
- return str_len_sum;
-}
-
/* Returns an auto_vec of string_slices containing the version strings from
ARGLIST. DEFAULT_COUNT is incremented for each default version found. */
@@ -7051,8 +7051,6 @@ extern unsigned fndecl_dealloc_argno (tree);
object or pointer. Otherwise return null. */
extern tree get_attr_nonstring_decl (tree, tree * = NULL);
-extern int get_target_clone_attr_len (tree);
-
/* Returns the version string for a decl with target_version attribute.
Returns an invalid string_slice if no attribute is present. */
extern string_slice get_target_version (const tree);