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

Reply via email to