https://gcc.gnu.org/g:ef26faa3ebf69727e6f73b430d935e390f9cb577

commit ef26faa3ebf69727e6f73b430d935e390f9cb577
Author: Alfie Richards <alfie.richa...@arm.com>
Date:   Thu Mar 27 14:12:06 2025 +0000

    Change function versions to be implicitly ordered.
    
    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): 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.

Diff:
---
 gcc/cgraph.cc                    | 50 ++++++++++++++++++++++------------------
 gcc/cgraph.h                     |  6 ++---
 gcc/config/aarch64/aarch64.cc    | 37 +++++++----------------------
 gcc/config/i386/i386-features.cc | 33 ++++----------------------
 gcc/config/riscv/riscv.cc        | 38 +++++-------------------------
 gcc/config/rs6000/rs6000.cc      | 35 +++++-----------------------
 gcc/cp/decl.cc                   |  8 ++++++-
 7 files changed, 63 insertions(+), 144 deletions(-)

diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc
index 6ae6a97f6f56..a2ad2516c12b 100644
--- a/gcc/cgraph.cc
+++ b/gcc/cgraph.cc
@@ -231,43 +231,49 @@ cgraph_node::delete_function_version_by_decl (tree decl)
   decl_node->remove ();
 }
 
-/* Record that DECL1 and DECL2 are semantically identical function
-   versions.  */
+/* Add decl to the structure of semantically identical function 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_node *decl_node = cgraph_node::get_create (decl);
+  cgraph_function_version_info *decl_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 ();
+  gcc_assert (decl_node != NULL);
+
+  decl_v = decl_node->function_version ();
 
-  if (decl1_v != NULL && decl2_v != NULL)
+  /* If the nodes are already linked, skip.  */
+  if (decl_v != NULL && (decl_v->next || decl_v->prev))
     return;
 
-  if (decl1_v == NULL)
-    decl1_v = decl1_node->insert_new_function_version ();
+  if (decl_v == NULL)
+    decl_v = decl_node->insert_new_function_version ();
 
-  if (decl2_v == NULL)
-    decl2_v = decl2_node->insert_new_function_version ();
+  gcc_assert (decl_v);
+  gcc_assert (fn_v);
 
-  /* Chain decl2_v and decl1_v.  All semantically identical versions
-     will be chained together.  */
+  before = fn_v;
+  after = decl_v;
 
-  before = decl1_v;
-  after = decl2_v;
+  /* Go to the beginning of both nodes (as after is on its own we just need to
+     this for before).  */
+  while (before->prev != NULL)
+    before = before->prev;
 
+  /* Potentially swap the nodes to maintain the default always being in the
+     first position.  */
+  if (is_function_default_version (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.  */
   before->next = after;
   after->prev = before;
 }
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 065fcc742e8b..6759505bf338 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 4e801146c60a..14a7518dfd70 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -20777,7 +20777,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;
 
@@ -20794,37 +20793,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 c35ac24fd8ae..2eb3a21bb5da 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 38f3ae7cd840..99f548785dbb 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -13735,7 +13735,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;
 
@@ -13752,41 +13751,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 737c3d6f7c75..c644d821b488 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 85c1b63c1f54..326bdb47c901 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -1310,7 +1310,13 @@ maybe_version_functions (tree newdecl, tree olddecl)
       maybe_mark_function_versioned (newdecl);
     }
 
-  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;
 }

Reply via email to