This hook is used to get the dispatcher function for a set of function
versions.  This function is copied from aarch64.

gcc/ChangeLog:

        * config/loongarch/loongarch.cc
        (loongarch_get_function_versions_dispatcher): New function.
        (TARGET_GET_FUNCTION_VERSIONS_DISPATCHER): Define.

---
 gcc/config/loongarch/loongarch.cc | 77 +++++++++++++++++++++++++++++++
 1 file changed, 77 insertions(+)

diff --git a/gcc/config/loongarch/loongarch.cc 
b/gcc/config/loongarch/loongarch.cc
index 65b8ff74d90..fd425a7b3e4 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -11352,6 +11352,79 @@ loongarch_option_valid_version_attribute_p (tree 
fndecl, tree, tree args, int)
   return ret;
 }
 
+/* Make a dispatcher declaration for the multi-versioned function DECL.
+   Calls to DECL function will be replaced with calls to the dispatcher
+   by the front-end.  Returns the decl of the dispatcher function.  */
+
+tree
+loongarch_get_function_versions_dispatcher (void *decl)
+{
+  tree fn = (tree) decl;
+  struct cgraph_node *node = NULL;
+  struct cgraph_node *default_node = NULL;
+  struct cgraph_function_version_info *node_v = NULL;
+
+  tree dispatch_decl = NULL;
+
+  struct cgraph_function_version_info *default_version_info = NULL;
+
+  gcc_assert (fn != NULL && DECL_FUNCTION_VERSIONED (fn));
+
+  node = cgraph_node::get (fn);
+  gcc_assert (node != NULL);
+
+  node_v = node->function_version ();
+  gcc_assert (node_v != NULL);
+
+  if (node_v->dispatcher_resolver != NULL)
+    return node_v->dispatcher_resolver;
+
+  /* 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 (!is_function_default_version (default_node->decl))
+    return NULL;
+
+  if (targetm.has_ifunc_p ())
+    {
+      struct cgraph_function_version_info *it_v = NULL;
+      struct cgraph_node *dispatcher_node = NULL;
+      struct cgraph_function_version_info *dispatcher_version_info = NULL;
+
+      /* Right now, the dispatching is done via ifunc.  */
+      dispatch_decl = make_dispatcher_decl (default_node->decl);
+      TREE_NOTHROW (dispatch_decl) = TREE_NOTHROW (fn);
+
+      dispatcher_node = cgraph_node::get_create (dispatch_decl);
+      gcc_assert (dispatcher_node != NULL);
+      dispatcher_node->dispatcher_function = 1;
+      dispatcher_version_info
+       = dispatcher_node->insert_new_function_version ();
+      dispatcher_version_info->next = default_version_info;
+      dispatcher_node->definition = 1;
+
+      /* Set the dispatcher for all the versions.  */
+      it_v = default_version_info;
+      while (it_v != NULL)
+       {
+         it_v->dispatcher_resolver = dispatch_decl;
+         it_v = it_v->next;
+       }
+    }
+  else
+    {
+      error_at (DECL_SOURCE_LOCATION (default_node->decl),
+               "multiversioning needs %<ifunc%> which is not supported "
+               "on this target");
+    }
+
+  return dispatch_decl;
+}
+
 /* Initialize the GCC target structure.  */
 #undef TARGET_ASM_ALIGNED_HI_OP
 #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
@@ -11639,6 +11712,10 @@ loongarch_option_valid_version_attribute_p (tree 
fndecl, tree, tree args, int)
 #define TARGET_OPTION_VALID_VERSION_ATTRIBUTE_P \
   loongarch_option_valid_version_attribute_p
 
+#undef TARGET_GET_FUNCTION_VERSIONS_DISPATCHER
+#define TARGET_GET_FUNCTION_VERSIONS_DISPATCHER \
+  loongarch_get_function_versions_dispatcher
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-loongarch.h"
-- 
2.34.1

Reply via email to