From 46ee0d6975bbea6246b83db08aa105c93d5fe3ef Mon Sep 17 00:00:00 2001 From: rfwang07 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 #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)