Alfie Richards <alfie.richa...@arm.com> writes: > 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 | 27 ++++++++++++++++----- > 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, 49 insertions(+), 124 deletions(-) > > diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc > index d0b19ad850e..bf6b43d00db 100644 > --- a/gcc/cgraph.cc > +++ b/gcc/cgraph.cc > @@ -247,7 +247,9 @@ cgraph_node::record_function_versions (tree decl1, tree > decl2) > decl1_v = decl1_node->function_version (); > decl2_v = decl2_node->function_version (); > > - if (decl1_v != NULL && decl2_v != NULL) > + /* If the nodes are already linked, skip. */ > + if ((decl1_v != NULL && (decl1_v->next || decl1_v->prev)) > + && (decl2_v != NULL && (decl2_v->next || decl2_v->prev))) > return; > > if (decl1_v == NULL) > @@ -256,18 +258,31 @@ cgraph_node::record_function_versions (tree decl1, tree > decl2) > 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; > + > + while (before->prev != NULL) > + before = before->prev; > + > + /* Potentially swap the nodes to maintain the default always being in the > + first position. */ > + if (before->next > + ? !is_function_default_version (before->this_node->decl) > + : is_function_default_version (after->this_node->decl)) > + std::swap (before, after); > + > + /* 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. */
I think this can be simplified to: before = decl1_v; after = decl2_v; /* Potentially swap the nodes to maintain the default always being in the first position. */ if (before->prev || before->next ? is_function_default_version (after->this_node->decl) : !is_function_default_version (before->this_node->decl)) std::swap (before, after); while (before->next != NULL) before = before->next; while (after->prev != NULL) after = after->prev; That is, if one decl is linked (and so the other is not), we only want to put the other decl first if it is the default. > [...] > diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc > index 9bf7713139f..e5aa99a4965 100644 > --- a/gcc/config/riscv/riscv.cc > +++ b/gcc/config/riscv/riscv.cc > @@ -13726,7 +13726,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; > > @@ -13743,41 +13742,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; My comment from the previous review still stands: I expect you were trying to avoid editorialising, but: how about converting this to is_function_default_version at the same time? That seems more logically consistent with the target-independent code and wasn't an option open to the RISC-V code until patch 5. To put it another way, not being able to use is_function_default_version here would suggest that the "default-first" assumption doesn't in fact hold for RISC-V. I.e. I think this can just be: if (!is_function_default_version (default_node->decl)) return NULL; as for the others. OK for GCC 16 with those changes, if you agree with them. Thanks, Richard