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 <[email protected]>
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