https://gcc.gnu.org/g:4969cb7dfba9cce1d88247fe8f365a6280ef62c6
commit r16-5151-g4969cb7dfba9cce1d88247fe8f365a6280ef62c6 Author: Lulu Cheng <[email protected]> Date: Fri Sep 19 16:13:01 2025 +0800 LoongArch: Implement TARGET_GET_FUNCTION_VERSIONS_DISPATCHER. 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. Diff: --- 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 c29e54b458d0..d74537f91461 100644 --- a/gcc/config/loongarch/loongarch.cc +++ b/gcc/config/loongarch/loongarch.cc @@ -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"
