https://gcc.gnu.org/g:1d5cfe644cd2047badb9e247dba2d3d9596e273e
commit 1d5cfe644cd2047badb9e247dba2d3d9596e273e Author: Alfie Richards <alfie.richa...@arm.com> Date: Thu Mar 27 14:12:06 2025 +0000 Refactor record_function_versions. Renames record_function_versions to add_function_version, and make it explicit that it is adding a single version to the function structure. Additionally, change the insertion point to always maintain priority ordering of the versions. This allows for removing logic for moving the default to the first position which was duplicated across target specific code and enables easier reasoning about function sets. gcc/ChangeLog: * cgraph.cc (cgraph_node::record_function_versions): Refactor and rename to... (cgraph_node::add_function_version): new function. * cgraph.h (cgraph_node::record_function_versions): Refactor and rename to... (cgraph_node::add_function_version): new function. * config/aarch64/aarch64.cc (aarch64_get_function_versions_dispatcher): Remove reordering. * config/i386/i386-features.cc (ix86_get_function_versions_dispatcher): Remove reordering. * config/riscv/riscv.cc (riscv_get_function_versions_dispatcher): Remove reordering. * config/rs6000/rs6000.cc (rs6000_get_function_versions_dispatcher): Remove reordering. gcc/cp/ChangeLog: * decl.cc (maybe_version_functions): Change record_function_versions call to add_function_version. (cherry picked from commit 5ed7e29d5d903f469d32d8f945f094e4c2881418) Diff: --- gcc/cgraph.cc | 75 ++++++++++++++++++++++++---------------- gcc/cgraph.h | 6 ++-- gcc/config/aarch64/aarch64.cc | 34 ++++-------------- gcc/config/i386/i386-features.cc | 34 ++++-------------- gcc/config/riscv/riscv.cc | 38 ++++---------------- gcc/config/rs6000/rs6000.cc | 35 ++++--------------- gcc/cp/decl.cc | 10 +++++- 7 files changed, 81 insertions(+), 151 deletions(-) diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc index 6ae6a97f6f56..feaeebec40ba 100644 --- a/gcc/cgraph.cc +++ b/gcc/cgraph.cc @@ -231,45 +231,60 @@ cgraph_node::delete_function_version_by_decl (tree decl) 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; - - gcc_assert (decl1_node != NULL && decl2_node != NULL); - decl1_v = decl1_node->function_version (); - decl2_v = decl2_node->function_version (); - - if (decl1_v != NULL && decl2_v != NULL) - return; - - if (decl1_v == NULL) - decl1_v = decl1_node->insert_new_function_version (); + cgraph_node *decl_node = cgraph_node::get_create (decl); + cgraph_function_version_info *decl_v = NULL; - if (decl2_v == NULL) - decl2_v = decl2_node->insert_new_function_version (); + gcc_assert (decl_node != NULL); - /* 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. */ diff --git a/gcc/cgraph.h b/gcc/cgraph.h index abde770ba2b3..ccb3dc77287f 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -1319,9 +1319,9 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node 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. */ diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index 08506e95a0aa..7789af0457c1 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -20791,7 +20791,6 @@ aarch64_get_function_versions_dispatcher (void *decl) 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; @@ -20808,37 +20807,16 @@ aarch64_get_function_versions_dispatcher (void *decl) 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; diff --git a/gcc/config/i386/i386-features.cc b/gcc/config/i386/i386-features.cc index c35ac24fd8ae..a26dd9c0f784 100644 --- a/gcc/config/i386/i386-features.cc +++ b/gcc/config/i386/i386-features.cc @@ -3962,7 +3962,6 @@ ix86_get_function_versions_dispatcher (void *decl) 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; @@ -3979,37 +3978,16 @@ ix86_get_function_versions_dispatcher (void *decl) 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 ()) { diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index afdacaf6b8a7..8fa1082f7c13 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -14051,7 +14051,6 @@ riscv_get_function_versions_dispatcher (void *decl) 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; @@ -14068,41 +14067,16 @@ riscv_get_function_versions_dispatcher (void *decl) 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; diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc index 12dbde2bc630..383d4f8b5971 100644 --- a/gcc/config/rs6000/rs6000.cc +++ b/gcc/config/rs6000/rs6000.cc @@ -25314,7 +25314,6 @@ rs6000_get_function_versions_dispatcher (void *decl) 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; @@ -25334,38 +25333,16 @@ rs6000_get_function_versions_dispatcher (void *decl) 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 " diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 4e97093b1341..a1741e3ef9ed 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -1313,7 +1313,15 @@ maybe_version_functions (tree newdecl, tree olddecl, bool record) } 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; }