This patch adds support for target_clones profile option. The target_clones profile option allows users to specify multiple versions of a function and select the version at runtime based on the specified profile.
The profile is formatted as a string of ':' separated pairs of assembler name and target_clones attribute string, one pair per line. The format of attribute string is target specific and should follow the target_clones attribute syntax. For the splitter of multiple target_clones attributes, we should follow the TARGET_CLONES_ATTR_SEPARATOR defined in each target. Currently, we use '#' for RISC-V and ',' for i386 and aarch64. A example of the profile is as follows on RISC-V: C source code "ror32.c": ``` void ror32(unsigned int *a, unsigned int b, unsigned long size) { for (unsigned long i = 0; i < size; i++) { a[i] = a[i] >> b | (a[i] << (32 - b)); } } ``` Profile "ror32.target_clones": ``` ror32:default#arch=+zvbb,+zbb#arch=+zbb ``` Then use: gcc -O3 -ftarget-profile=ror32.target_clones -S ror32.c to compile the source code. This will generate 3 versions and its IFUNC resolver for the ror32 function which is "arch=+zvbb,+zbb" and "arch=+zbb" and the default version. Signed-off-by: Yangyu Chen <c...@cyyself.name> gcc/ChangeLog: * common.opt: Add target_clones profile option. * multiple_target.cc (expand_target_clones): Add support for target_clones profile option. * opts.cc (common_handle_option): Ditto. --- gcc/common.opt | 7 +++++++ gcc/multiple_target.cc | 24 +++++++++++++++++++++++- gcc/opts.cc | 23 +++++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/gcc/common.opt b/gcc/common.opt index 0e50305dde8..31d7c879c81 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -2688,6 +2688,13 @@ fprofile-reorder-functions Common Var(flag_profile_reorder_functions) Optimization Enable function reordering that improves code placement. +ftarget-profile= +Common Joined RejectNegative Var(target_profile) +Enable target_clones profile options. + +Variable +void *target_profile_map = NULL + fpatchable-function-entry= Common Var(flag_patchable_function_entry) Joined Optimization Insert NOP instructions at each function entry. diff --git a/gcc/multiple_target.cc b/gcc/multiple_target.cc index d25277c0a93..4b8a7da2308 100644 --- a/gcc/multiple_target.cc +++ b/gcc/multiple_target.cc @@ -38,6 +38,8 @@ along with GCC; see the file COPYING3. If not see #include "gimple-walk.h" #include "tree-inline.h" #include "intl.h" +#include <string> +#include <map> /* Walker callback that replaces all FUNCTION_DECL of a function that's going to be versioned. */ @@ -319,7 +321,27 @@ expand_target_clones (struct cgraph_node *node, bool definition) DECL_ATTRIBUTES (node->decl)); /* No targets specified. */ if (!attr_target) - return false; + { + /* Skip functions that are declared but not defined. */ + if (target_profile != NULL && DECL_INITIAL (node->decl) != NULL_TREE) + { + auto profile_map + = static_cast<std::map <std::string, std::string> *> + (target_profile_map); + auto it = profile_map->find (IDENTIFIER_POINTER ( + DECL_ASSEMBLER_NAME_RAW (node->decl))); + if (it != profile_map->end ()) + { + attr_target = make_attribute ("target_clones", + it->second.c_str (), + DECL_ATTRIBUTES (node->decl)); + } + else + return false; + } + else + return false; + } tree arglist = TREE_VALUE (attr_target); int attr_len = get_target_clone_attr_len (arglist); diff --git a/gcc/opts.cc b/gcc/opts.cc index a9b9b9148a9..6ae004e6653 100644 --- a/gcc/opts.cc +++ b/gcc/opts.cc @@ -36,6 +36,9 @@ along with GCC; see the file COPYING3. If not see #include "version.h" #include "selftest.h" #include "file-prefix-map.h" +#include <fstream> +#include <string> +#include <map> /* In this file all option sets are explicit. */ #undef OPTION_SET_P @@ -3160,6 +3163,26 @@ common_handle_option (struct gcc_options *opts, case OPT_fprofile_info_section: opts->x_profile_info_section = ".gcov_info"; break; + case OPT_ftarget_profile_: + { + std::ifstream profile_file; + profile_file.open (arg); + if (profile_file.fail ()) + error_at (loc, "cannot open profile file %qs: %m", arg); + std::map <std::string, std::string> *profile_map + = new std::map<std::string, std::string>(); + opts->x_target_profile_map = profile_map; + std::string line; + while (std::getline (profile_file, line)) + { + std::string::size_type pos = line.find (':'); + if (pos == std::string::npos) + error_at (loc, "invalid profile file format"); + profile_map->insert (std::make_pair (line.substr (0, pos), + line.substr (pos + 1))); + } + break; + } case OPT_fpatchable_function_entry_: { -- 2.49.0