decl_node->remove ();
}
-/* Record that DECL1 and DECL2 are semantically identical function
+/* Add decl to the structure of semantically identical function versions.
+ The node is inserted at the point maintaining the priority ordering on the
versions. */
void
-cgraph_node::record_function_versions (tree decl1, tree decl2)
+cgraph_node::add_function_version (cgraph_function_version_info *fn_v,
+ tree decl)
{
- cgraph_node *decl1_node = cgraph_node::get_create (decl1);
- cgraph_node *decl2_node = cgraph_node::get_create (decl2);
- cgraph_function_version_info *decl1_v = NULL;
- cgraph_function_version_info *decl2_v = NULL;
- cgraph_function_version_info *before;
- cgraph_function_version_info *after;
+ cgraph_node *decl_node = cgraph_node::get_create (decl);
+ cgraph_function_version_info *decl_v = NULL;
- gcc_assert (decl1_node != NULL && decl2_node != NULL);
- decl1_v = decl1_node->function_version ();
- decl2_v = decl2_node->function_version ();
+ gcc_assert (decl_node != NULL);
- if (decl1_v != NULL && decl2_v != NULL)
- return;
-
- if (decl1_v == NULL)
- decl1_v = decl1_node->insert_new_function_version ();
-
- if (decl2_v == NULL)
- decl2_v = decl2_node->insert_new_function_version ();
-
- /* Chain decl2_v and decl1_v. All semantically identical versions
- will be chained together. */
+ decl_v = decl_node->function_version ();
- before = decl1_v;
- after = decl2_v;
+ /* If the nodes are already linked, skip. */
+ if (decl_v != NULL && (decl_v->next || decl_v->prev))
+ return;
- while (before->next != NULL)
- before = before->next;
+ if (decl_v == NULL)
+ decl_v = decl_node->insert_new_function_version ();
+
+ gcc_assert (decl_v);
+ gcc_assert (fn_v);
+
+ /* Go to start of the FMV structure. */
+ while (fn_v->prev)
+ fn_v = fn_v->prev;
+
+ cgraph_function_version_info *insert_point_before = NULL;
+ cgraph_function_version_info *insert_point_after = fn_v;
+
+ /* Find the insertion point for the new version to maintain ordering.
+ The default node must always go at the beginning. */
+ if (!is_function_default_version (decl))
+ while (insert_point_after
+ && (targetm.compare_version_priority
+ (decl, insert_point_after->this_node->decl) > 0
+ || is_function_default_version
+ (insert_point_after->this_node->decl)
+ || lookup_attribute
+ ("target_clones",
+ DECL_ATTRIBUTES (insert_point_after->this_node->decl))))
+ {
+ insert_point_before = insert_point_after;
+ insert_point_after = insert_point_after->next;
+ }
- while (after->prev != NULL)
- after= after->prev;
+ decl_v->prev = insert_point_before;
+ decl_v->next= insert_point_after;
- before->next = after;
- after->prev = before;
+ if (insert_point_before)
+ insert_point_before->next = decl_v;
+ if (insert_point_after)
+ insert_point_after->prev = decl_v;
}
/* Initialize callgraph dump file. */
return m_summary_id;
}
- /* Record that DECL1 and DECL2 are semantically identical function
- versions. */
- static void record_function_versions (tree decl1, tree decl2);
+ /* Adds DECL to the FN_V structure of semantically identical functions. */
+ static void add_function_version (cgraph_function_version_info *fn_v,
+ tree decl);
/* Remove the cgraph_function_version_info and cgraph_node for DECL. This
DECL is a duplicate declaration. */
struct cgraph_node *node = NULL;
struct cgraph_node *default_node = NULL;
struct cgraph_function_version_info *node_v = NULL;
- struct cgraph_function_version_info *first_v = NULL;
tree dispatch_decl = NULL;
if (node_v->dispatcher_resolver != NULL)
return node_v->dispatcher_resolver;
- /* Find the default version and make it the first node. */
- first_v = node_v;
- /* Go to the beginning of the chain. */
- while (first_v->prev != NULL)
- first_v = first_v->prev;
- default_version_info = first_v;
- while (default_version_info != NULL)
- {
- if (get_feature_mask_for_version
- (default_version_info->this_node->decl) == 0ULL)
- break;
- default_version_info = default_version_info->next;
- }
+ /* The default node is always the beginning of the chain. */
+ default_version_info = node_v;
+ while (default_version_info->prev)
+ default_version_info = default_version_info->prev;
+ default_node = default_version_info->this_node;
/* If there is no default node, just return NULL. */
- if (default_version_info == NULL)
+ if (!is_function_default_version (default_node->decl))
return NULL;
- /* Make default info the first node. */
- if (first_v != default_version_info)
- {
- default_version_info->prev->next = default_version_info->next;
- if (default_version_info->next)
- default_version_info->next->prev = default_version_info->prev;
- first_v->prev = default_version_info;
- default_version_info->next = first_v;
- default_version_info->prev = NULL;
- }
-
- default_node = default_version_info->this_node;
-
if (targetm.has_ifunc_p ())
{
struct cgraph_function_version_info *it_v = NULL;
struct cgraph_node *node = NULL;
struct cgraph_node *default_node = NULL;
struct cgraph_function_version_info *node_v = NULL;
- struct cgraph_function_version_info *first_v = NULL;
tree dispatch_decl = NULL;
if (node_v->dispatcher_resolver != NULL)
return node_v->dispatcher_resolver;
- /* Find the default version and make it the first node. */
- first_v = node_v;
- /* Go to the beginning of the chain. */
- while (first_v->prev != NULL)
- first_v = first_v->prev;
- default_version_info = first_v;
- while (default_version_info != NULL)
- {
- if (is_function_default_version
- (default_version_info->this_node->decl))
- break;
- default_version_info = default_version_info->next;
- }
+ /* The default node is always the beginning of the chain. */
+ 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 (default_version_info == NULL)
+ if (!is_function_default_version (default_node->decl))
return NULL;
- /* Make default info the first node. */
- if (first_v != default_version_info)
- {
- default_version_info->prev->next = default_version_info->next;
- if (default_version_info->next)
- default_version_info->next->prev = default_version_info->prev;
- first_v->prev = default_version_info;
- default_version_info->next = first_v;
- default_version_info->prev = NULL;
- }
-
- default_node = default_version_info->this_node;
-
#if defined (ASM_OUTPUT_TYPE_DIRECTIVE)
if (targetm.has_ifunc_p ())
{
struct cgraph_node *node = NULL;
struct cgraph_node *default_node = NULL;
struct cgraph_function_version_info *node_v = NULL;
- struct cgraph_function_version_info *first_v = NULL;
tree dispatch_decl = NULL;
if (node_v->dispatcher_resolver != NULL)
return node_v->dispatcher_resolver;
- /* Find the default version and make it the first node. */
- first_v = node_v;
- /* Go to the beginning of the chain. */
- while (first_v->prev != NULL)
- first_v = first_v->prev;
- default_version_info = first_v;
-
- while (default_version_info != NULL)
- {
- struct riscv_feature_bits res;
- int priority; /* Unused. */
- parse_features_for_version (default_version_info->this_node->decl,
- res, priority);
- if (res.length == 0)
- break;
- default_version_info = default_version_info->next;
- }
+ /* The default node is always the beginning of the chain. */
+ default_version_info = node_v;
+ while (default_version_info->prev)
+ default_version_info = default_version_info->prev;
+ default_node = default_version_info->this_node;
/* If there is no default node, just return NULL. */
- if (default_version_info == NULL)
+ if (!is_function_default_version (default_node->decl))
return NULL;
- /* Make default info the first node. */
- if (first_v != default_version_info)
- {
- default_version_info->prev->next = default_version_info->next;
- if (default_version_info->next)
- default_version_info->next->prev = default_version_info->prev;
- first_v->prev = default_version_info;
- default_version_info->next = first_v;
- default_version_info->prev = NULL;
- }
-
- default_node = default_version_info->this_node;
-
if (targetm.has_ifunc_p ())
{
struct cgraph_function_version_info *it_v = NULL;
struct cgraph_node *node = NULL;
struct cgraph_node *default_node = NULL;
struct cgraph_function_version_info *node_v = NULL;
- struct cgraph_function_version_info *first_v = NULL;
tree dispatch_decl = NULL;
if (node_v->dispatcher_resolver != NULL)
return node_v->dispatcher_resolver;
- /* Find the default version and make it the first node. */
- first_v = node_v;
- /* Go to the beginning of the chain. */
- while (first_v->prev != NULL)
- first_v = first_v->prev;
-
- default_version_info = first_v;
- while (default_version_info != NULL)
- {
- const tree decl2 = default_version_info->this_node->decl;
- if (is_function_default_version (decl2))
- break;
- default_version_info = default_version_info->next;
- }
+ /* The default node is always the beginning of the chain. */
+ default_version_info = node_v;
+ while (default_version_info->prev)
+ default_version_info = default_version_info->prev;
+ default_node = default_version_info->this_node;
/* If there is no default node, just return NULL. */
- if (default_version_info == NULL)
+ if (!is_function_default_version (default_node->decl))
return NULL;
- /* Make default info the first node. */
- if (first_v != default_version_info)
- {
- default_version_info->prev->next = default_version_info->next;
- if (default_version_info->next)
- default_version_info->next->prev = default_version_info->prev;
- first_v->prev = default_version_info;
- default_version_info->next = first_v;
- default_version_info->prev = NULL;
- }
-
- default_node = default_version_info->this_node;
-
#ifndef TARGET_LIBC_PROVIDES_HWCAP_IN_TCB
error_at (DECL_SOURCE_LOCATION (default_node->decl),
"%<target_clones%> attribute needs GLIBC (2.23 and newer) that "
}
if (record)
- cgraph_node::record_function_versions (olddecl, newdecl);
+ {
+ /* Add the new version to the function version structure. */
+ cgraph_node *fn_node = cgraph_node::get_create (olddecl);
+ cgraph_function_version_info *fn_v = fn_node->function_version ();
+ if (!fn_v)
+ fn_v = fn_node->insert_new_function_version ();
+
+ cgraph_node::add_function_version (fn_v, newdecl);
+ }
return true;
}