]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
LoongArch: Implement TARGET_GET_FUNCTION_VERSIONS_DISPATCHER.
authorLulu Cheng <chenglulu@loongson.cn>
Fri, 19 Sep 2025 08:13:01 +0000 (16:13 +0800)
committerLulu Cheng <chenglulu@loongson.cn>
Tue, 11 Nov 2025 07:33:36 +0000 (15:33 +0800)
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

index c29e54b458d08188f17eb49c35c1ad252bfd1f89..d74537f91461f93a15ea2026fd0480810cc97d96 100644 (file)
@@ -11524,6 +11524,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"
@@ -11815,6 +11888,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"