gcc/0200-Support-LTO-in-AutoBOLT-mode.patch
2024-06-15 18:19:56 +08:00

422 lines
12 KiB
Diff

From 46ee0d6975bbea6246b83db08aa105c93d5fe3ef Mon Sep 17 00:00:00 2001
From: rfwang07 <wangrufeng5@huawei.com>
Date: Sat, 15 Jun 2024 12:59:51 +0800
Subject: [PATCH] Support LTO in AutoBOLT mode
---
bolt-plugin/bolt-plugin.cc | 35 +++++--
gcc/common.opt | 4 +-
gcc/final.c | 191 ++++++++++++++++++++++++++++++++-----
gcc/opts.c | 7 +-
4 files changed, 196 insertions(+), 41 deletions(-)
diff --git a/bolt-plugin/bolt-plugin.cc b/bolt-plugin/bolt-plugin.cc
index f357b00dd..06cf1911a 100644
--- a/bolt-plugin/bolt-plugin.cc
+++ b/bolt-plugin/bolt-plugin.cc
@@ -269,6 +269,8 @@ static string tmp_out_file_name = "a.out";
/* Binary or dynamic file after BOLT. */
static string bolt_opt_target;
+static bool autobolt_with_lto = false;
+
/* Format of bolt_optimize_options should be "reorder-functions=hfsort+ ...",
command 'llvm-bolt' has been added here. */
static string bolt_optimize_options ("llvm-bolt ");
@@ -450,9 +452,9 @@ cleanup_handler ()
fclose (bolt_file_fd);
}
- if (file_exist (tmp_out_file_name.c_str ())
- && file_exist (bolt_profile_name.c_str ())
- && is_bolt_opt_target ())
+ if (is_bolt_opt_target ()
+ && file_exist (tmp_out_file_name.c_str ())
+ && file_exist (bolt_profile_name.c_str ()))
{
do_bolt_opt ();
}
@@ -552,6 +554,10 @@ dump_func_to_bolt_profile_file (const struct func_info &func)
static enum ld_plugin_status
all_symbols_read_handler ()
{
+ if (autobolt_with_lto)
+ {
+ return LDPS_OK;
+ }
for (const auto &functions: weak_functions)
{
/* More than one weak function. */
@@ -748,7 +754,10 @@ claim_file_handler (const struct ld_plugin_input_file *file, int *claimed)
}
/* BOLT plugin does not need claimd number, so set *claimed to 0. */
*claimed = 0;
-
+ if (autobolt_with_lto)
+ {
+ return LDPS_OK;
+ }
obj.file = file;
obj.objfile = simple_object_start_read (file->fd, file->offset, NULL,
&errmsg, &err);
@@ -823,9 +832,12 @@ generate_bolt_profile_name (string file_name)
{
if (!bolt_dir_path.empty ())
{
- file_name = concat (get_current_dir_name (),
- separator, file_name.c_str (), NULL);
- file_name = mangle_path (file_name);
+ if (!autobolt_with_lto)
+ {
+ file_name = concat (get_current_dir_name (),
+ separator, file_name.c_str (), NULL);
+ file_name = mangle_path (file_name);
+ }
}
else
{
@@ -1019,7 +1031,10 @@ process_output_option (const string &flag_o)
/* bolt_profile_name may be overridden in
function process_auto_bolt_option and
process_bolt_use_option. */
- bolt_profile_name = gcc_options[o_index + 1];
+ if (autobolt_with_lto && bolt_opt_target.empty ())
+ bolt_profile_name = "default";
+ else
+ bolt_profile_name = gcc_options[o_index + 1];
bolt_profile_name.append (DEFAULT_BOLT_OUT_NAME_SUFFIX);
}
else
@@ -1047,13 +1062,15 @@ process_gcc_option ()
char *collect_gcc_option = getenv ("COLLECT_GCC_OPTIONS");
get_options_from_collect_gcc_options (collect_gcc, collect_gcc_option);
+ autobolt_with_lto = (match_gcc_option (flag_auto_bolt.c_str ()) != -1
+ && match_gcc_option ("-flto") != -1);
+ process_bolt_target_option (flag_bolt_target);
/* Function process_output_option should be processed before
process_auto_bolt_option to obtain correct bolt_profile_name. */
process_output_option (flag_o);
process_auto_bolt_option (flag_auto_bolt);
process_bolt_use_option (flag_bolt_use);
- process_bolt_target_option (flag_bolt_target);
process_bolt_option (flag_bolt_optimize_options);
if (match_gcc_option (flag_profile_use.c_str ()) != -1)
diff --git a/gcc/common.opt b/gcc/common.opt
index ea55355be..aad6fb281 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2482,7 +2482,7 @@ Common Report Var(flag_auto_bolt)
Generate profile from AutoFDO or PGO and do BOLT optimization after linkage.
fauto-bolt=
-Common Joined RejectNegative
+Common Joined RejectNegative Var(auto_bolt)
Specify the feedback data directory required by BOLT-plugin. The default is the current directory.
fbolt-use
@@ -2494,7 +2494,7 @@ Common Joined RejectNegative Var
Do BOLT optimization after linkage with BOLT profile read from this option.
fbolt-target=
-Common Joined RejectNegative Var
+Common Joined RejectNegative Var(bolt_target)
Specify the BOLT optimization target binary.
fbolt-option=
diff --git a/gcc/final.c b/gcc/final.c
index da8d20958..807384514 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -82,6 +82,7 @@ along with GCC; see the file COPYING3. If not see
#include "print-rtl.h"
#include "function-abi.h"
#include "insn-codes.h"
+#include <sys/file.h>
#ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h" /* Needed for external data declarations. */
@@ -4650,6 +4651,10 @@ leaf_renumber_regs_insn (rtx in_rtx)
#define ASM_FDO_CALLEE_FLAG ".fdo.callee "
+static bool autobolt_with_lto = false;
+static char *autobolt_curr_func_name;
+static FILE *bolt_file_fd = NULL;
+
/* Return the relative offset address of the start instruction of BB,
return -1 if it is empty instruction. */
@@ -4785,6 +4790,16 @@ alias_local_functions (const char *fnname)
return concat (fnname, "/", lbasename (dump_base_name), NULL);
}
+static char*
+add_suffix (const char *str)
+{
+ if (strlen (str) == 0 || strstr (str, "/") == NULL)
+ {
+ return xstrdup (str);
+ }
+ return concat (str, "/1", NULL);
+}
+
/* Return function bind type string. */
static const char *
@@ -4830,19 +4845,33 @@ dump_direct_callee_info_to_asm (basic_block bb, gcov_type call_count)
if (callee)
{
- char *func_name =
- alias_local_functions (get_fnname_from_decl (callee));
- fprintf (asm_out_file, "\t.string \"%x\"\n",
- INSN_ADDRESSES (INSN_UID (insn)));
-
- fprintf (asm_out_file, "\t.string \"%s%s\"\n",
- ASM_FDO_CALLEE_FLAG,
- func_name);
-
- fprintf (asm_out_file,
- "\t.string \"" HOST_WIDE_INT_PRINT_DEC "\"\n",
- call_count);
-
+ char *func_name;
+ if (!autobolt_with_lto)
+ {
+ func_name = alias_local_functions (
+ get_fnname_from_decl (callee));
+ fprintf (asm_out_file, "\t.string \"%x\"\n",
+ INSN_ADDRESSES (INSN_UID (insn)));
+
+ fprintf (asm_out_file, "\t.string \"%s%s\"\n",
+ ASM_FDO_CALLEE_FLAG,
+ func_name);
+
+ fprintf (asm_out_file,
+ "\t.string \"" HOST_WIDE_INT_PRINT_DEC "\"\n",
+ call_count);
+ }
+ else
+ {
+ func_name = xstrdup (
+ get_fnname_from_decl (callee));
+ fprintf (bolt_file_fd,
+ "1 %s %x 1 %s 0 0 " HOST_WIDE_INT_PRINT_DEC "\n",
+ autobolt_curr_func_name,
+ INSN_ADDRESSES (INSN_UID (insn)),
+ func_name,
+ call_count);
+ }
if (dump_file)
{
fprintf (dump_file, "call: %x --> %s\n",
@@ -4880,7 +4909,10 @@ dump_edge_jump_info_to_asm (basic_block bb, gcov_type bb_count)
/* This is a reserved assert for the original design. If this
assert is found, use the address of the previous instruction
as edge_start_addr. */
- gcc_assert (edge_start_addr != edge_end_addr);
+ if (edge_start_addr == edge_end_addr)
+ {
+ continue;
+ }
if (dump_file)
{
@@ -4890,10 +4922,24 @@ dump_edge_jump_info_to_asm (basic_block bb, gcov_type bb_count)
if (edge_count > 0)
{
- fprintf (asm_out_file, "\t.string \"%x\"\n", edge_start_addr);
- fprintf (asm_out_file, "\t.string \"%x\"\n", edge_end_addr);
- fprintf (asm_out_file, "\t.string \"" HOST_WIDE_INT_PRINT_DEC "\"\n",
- edge_count);
+ if (!autobolt_with_lto)
+ {
+ fprintf (asm_out_file, "\t.string \"%x\"\n", edge_start_addr);
+ fprintf (asm_out_file, "\t.string \"%x\"\n", edge_end_addr);
+ fprintf (asm_out_file,
+ "\t.string \"" HOST_WIDE_INT_PRINT_DEC "\"\n",
+ edge_count);
+ }
+ else
+ {
+ fprintf (bolt_file_fd,
+ "1 %s %x 1 %s %x 0 " HOST_WIDE_INT_PRINT_DEC "\n",
+ autobolt_curr_func_name,
+ edge_start_addr,
+ autobolt_curr_func_name,
+ edge_end_addr,
+ edge_count);
+ }
}
}
@@ -4924,12 +4970,17 @@ static void
dump_function_info_to_asm (const char *fnname)
{
char *func_name = alias_local_functions (fnname);
- fprintf (asm_out_file, "\t.string \"%s%s\"\n",
- ASM_FDO_CALLER_FLAG, func_name);
- fprintf (asm_out_file, "\t.string \"%s%d\"\n",
- ASM_FDO_CALLER_SIZE_FLAG, get_function_end_addr ());
- fprintf (asm_out_file, "\t.string \"%s%s\"\n",
- ASM_FDO_CALLER_BIND_FLAG, simple_get_function_bind ());
+ if (!autobolt_with_lto)
+ {
+ fprintf (asm_out_file, "\t.string \"%s%s\"\n",
+ ASM_FDO_CALLER_FLAG, func_name);
+ fprintf (asm_out_file, "\t.string \"%s%d\"\n",
+ ASM_FDO_CALLER_SIZE_FLAG,
+ get_function_end_addr ());
+ fprintf (asm_out_file, "\t.string \"%s%s\"\n",
+ ASM_FDO_CALLER_BIND_FLAG,
+ simple_get_function_bind ());
+ }
if (dump_file)
{
@@ -5041,6 +5092,90 @@ dump_profile_to_elf_sections ()
}
}
+#define DEFAULT_BOLT_OUT_NAME "default.fdata"
+static char *bolt_profile_name = DEFAULT_BOLT_OUT_NAME;
+static void
+open_bolt_profile_file ()
+{
+ char *file_path;
+
+ if (auto_bolt && strlen (auto_bolt) != 0)
+ file_path = lrealpath (auto_bolt);
+ else
+ file_path = lrealpath (dump_dir_name);
+ if (bolt_target && strlen (bolt_target) != 0)
+ bolt_profile_name = concat (
+ file_path, "/", lbasename (bolt_target), ".fdata", NULL);
+ else
+ bolt_profile_name = concat (
+ file_path, "/", DEFAULT_BOLT_OUT_NAME, NULL);
+ free (file_path);
+
+ if (bolt_file_fd == NULL)
+ {
+ bolt_file_fd = fopen (bolt_profile_name, "at");
+ if (!bolt_file_fd)
+ {
+ error ("Failed to open the file: %s."
+ " Please check whether the target path exists.",
+ bolt_profile_name);
+ }
+ if (flock (fileno (bolt_file_fd), LOCK_EX) == -1)
+ {
+ error ("Failed to lock the file: %s.",
+ bolt_profile_name);
+ }
+ }
+ free (bolt_profile_name);
+}
+
+inline static bool
+is_bolt_opt_target ()
+{
+ bool is_target = true;
+ if (bolt_target && strlen (bolt_target) != 0)
+ {
+ char *target_name = concat (lbasename (bolt_target),
+ ".ltrans", NULL);
+ if (strncmp (target_name,
+ lbasename (dump_base_name),
+ strlen (target_name)) != 0)
+ {
+ is_target = false;
+ }
+ free (target_name);
+ }
+ return is_target;
+}
+
+static void
+dump_profile_to_bolt_file ()
+{
+ /* Avoid empty functions. */
+ if (TREE_CODE (cfun->decl) != FUNCTION_DECL)
+ {
+ return;
+ }
+
+ if (!is_bolt_opt_target ())
+ {
+ return;
+ }
+
+ open_bolt_profile_file ();
+ const char *fnname = get_fnname_from_decl (current_function_decl);
+ autobolt_curr_func_name = add_suffix (fnname);
+ dump_fdo_info_to_asm (fnname);
+ free (autobolt_curr_func_name);
+ fflush (bolt_file_fd);
+ if (flock (fileno (bolt_file_fd), LOCK_UN) == -1)
+ {
+ error ("Failed to unlock the file: %s.", bolt_profile_name);
+ }
+ fclose (bolt_file_fd);
+ bolt_file_fd = NULL;
+}
+
/* Turn the RTL into assembly. */
static unsigned int
rest_of_handle_final (void)
@@ -5111,7 +5246,13 @@ rest_of_handle_final (void)
if (flag_auto_bolt)
{
- dump_profile_to_elf_sections ();
+ if (flag_ltrans)
+ {
+ autobolt_with_lto = true;
+ dump_profile_to_bolt_file ();
+ }
+ else
+ dump_profile_to_elf_sections ();
}
return 0;
diff --git a/gcc/opts.c b/gcc/opts.c
index 30ac57eec..c0ccd0853 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -1166,10 +1166,6 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
if (opts->x_flag_vtable_verify && opts->x_flag_lto)
sorry ("vtable verification is not supported with LTO");
- /* Currently -fauto-bolt is not supported for LTO. */
- if (opts->x_flag_auto_bolt && opts->x_flag_lto)
- sorry ("%<-fauto-bolt%> is not supported with LTO");
-
/* Currently -fbolt-use is not supported for LTO. */
if (opts->x_flag_bolt_use && opts->x_flag_lto)
sorry ("-fbolt-use is not supported with LTO");
@@ -2970,6 +2966,7 @@ common_handle_option (struct gcc_options *opts,
case OPT_fauto_bolt_:
opts->x_flag_auto_bolt = true;
+ opts->x_auto_bolt = xstrdup (arg);
/* FALLTHRU */
case OPT_fauto_bolt:
if (opts->x_flag_bolt_use)
@@ -2985,7 +2982,7 @@ common_handle_option (struct gcc_options *opts,
break;
case OPT_fbolt_target_:
- /* Deferred. */
+ opts->x_bolt_target = xstrdup (arg);
break;
case OPT_fbolt_option_:
--
2.39.2 (Apple Git-143)