This changes function version structures to maintain the default version as the first declaration in the linked data structures by giving priority to the set containing the default when constructing the structure.
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 when checking for a default. gcc/ChangeLog: * cgraph.cc (cgraph_node::record_function_versions): Update to implicitly keep default first. * 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/cgraph.cc | 39 +++++++++++++++++++++++------- gcc/config/aarch64/aarch64.cc | 37 +++++++--------------------- gcc/config/i386/i386-features.cc | 33 ++++--------------------- gcc/config/riscv/riscv.cc | 41 +++++++------------------------- gcc/config/rs6000/rs6000.cc | 35 +++++---------------------- 5 files changed, 58 insertions(+), 127 deletions(-)
diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc index d0b19ad850e..1ea38d16e56 100644 --- a/gcc/cgraph.cc +++ b/gcc/cgraph.cc @@ -236,37 +236,58 @@ cgraph_node::delete_function_version_by_decl (tree decl) void cgraph_node::record_function_versions (tree decl1, tree decl2) { - cgraph_node *decl1_node = cgraph_node::get_create (decl1); - cgraph_node *decl2_node = cgraph_node::get_create (decl2); + cgraph_node *decl1_node; + cgraph_node *decl2_node; 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_function_version_info *temp_node; + + decl1_node = cgraph_node::get_create (decl1); + decl2_node = cgraph_node::get_create (decl2); 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 (); 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. */ + gcc_assert (decl1_v); + gcc_assert (decl2_v); before = decl1_v; after = decl2_v; + /* Go to first after node. */ + while (after->prev != NULL) + after = after->prev; + + /* Go to first before node. */ + while (before->prev != NULL) + before = before->prev; + + /* These are already recorded as versions. */ + if (before == after) + return; + + /* Possibly swap to make sure the default node stays at the front. */ + if (is_function_default_version (after->this_node->decl)) + { + temp_node = after; + after = before; + before = temp_node; + } + + /* Go to last node of before. */ while (before->next != NULL) before = before->next; - while (after->prev != NULL) - after= after->prev; + /* Chain decl2_v and decl1_v. */ before->next = after; after->prev = before; diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index be99137b052..15dd7dda48a 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -20630,7 +20630,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; @@ -20647,37 +20646,17 @@ 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; - } - - /* If there is no default node, just return NULL. */ - if (default_version_info == NULL) - 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; - } + /* 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 version, just return NULL. */ + if (!is_function_default_version (default_node->decl)) + return NULL; + 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 c35ac24fd8a..2eb3a21bb5d 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,15 @@ 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; /* 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 439cc12f93d..69e47ec7e79 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -13719,7 +13719,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; @@ -13736,41 +13735,19 @@ 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) + struct riscv_feature_bits res; + int priority; /* Unused. */ + parse_features_for_version (default_node->decl, res, priority); + if (res.length != 0) 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 675b039c2b6..c59bd43c76d 100644 --- a/gcc/config/rs6000/rs6000.cc +++ b/gcc/config/rs6000/rs6000.cc @@ -25295,7 +25295,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; @@ -25315,38 +25314,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 "