From 0de967c51189535f8d00943ccc91a3ad07e50ef2 Mon Sep 17 00:00:00 2001 From: wangchunyang Date: Wed, 11 Sep 2024 17:27:19 +0800 Subject: [PATCH 4/5] add flag -flto-try enable LTO and automatically skip in inapplicable situation. --- gcc/collect2.cc | 51 ++++++++++++++++++++++++++++++++++++++++++- gcc/common.opt | 8 +++++++ gcc/opts-common.cc | 54 +++++++++++++++++++++++++++++++++++++++++++++- gcc/opts.cc | 20 +++++++++++++++++ 4 files changed, 131 insertions(+), 2 deletions(-) diff --git a/gcc/collect2.cc b/gcc/collect2.cc index 9715e8eee..690363880 100644 --- a/gcc/collect2.cc +++ b/gcc/collect2.cc @@ -200,6 +200,7 @@ static enum lto_mode_d lto_mode = LTO_MODE_WHOPR; #else static enum lto_mode_d lto_mode = LTO_MODE_NONE; #endif +static bool maybe_relink_without_lto = false; bool helpflag; /* true if --help */ @@ -751,7 +752,53 @@ do_link (char **ld_argv, const char *atsuffix) PEX_LAST | PEX_SEARCH, HAVE_GNU_LD && at_file_supplied, atsuffix); int ret = collect_wait (prog, pex); - if (ret) + if (ret && maybe_relink_without_lto) + { + bool link_with_lto_plugin_before = false; + for (int i = 0, j = -1; ld_argv[i]; ++i) + { + if (endswith (ld_argv[i], "liblto_plugin.so")) + { + link_with_lto_plugin_before = true; + for (j = i + 1; ld_argv[j]; ++j) + { + if (!startswith (ld_argv[j], "-plugin-opt=")) + break; + } + for (i = i - 1; ; ++i, ++j) + { + ld_argv[i] = ld_argv[j]; + if (ld_argv[j] == NULL) + break; + } + break; + } + } + int ret2 = 0; + if (link_with_lto_plugin_before) + { + fprintf (stderr, "lto link fail, relinking without lto"); + lto_mode = LTO_MODE_NONE; + pex = collect_execute (prog, ld_argv, NULL, NULL, + PEX_LAST | PEX_SEARCH, + HAVE_GNU_LD && at_file_supplied, atsuffix); + ret2 = collect_wait (prog, pex); + } + else + ret2 = ret; + if (ret2) + { + error ("ld returned %d exit status", ret); + exit (ret); + } + else + { + /* We have just successfully produced an output file, so assume that + we may unlink it if need be for now on. */ + may_unlink_output_file = true; + } + } + else if (ret) { error ("ld returned %d exit status", ret); exit (ret); @@ -1009,6 +1056,8 @@ main (int argc, char **argv) num_c_args++; if (startswith (q, "-flto-partition=none")) no_partition = true; + else if (startswith (q, "-flto-try")) + maybe_relink_without_lto = true; else if (startswith (q, "-fno-lto")) lto_mode = LTO_MODE_NONE; else if (startswith (q, "-save-temps")) diff --git a/gcc/common.opt b/gcc/common.opt index 96888cf1b..0895c6114 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -70,6 +70,10 @@ bool flag_warn_unused_result = false Variable int flag_generate_lto +; Nonzero if we should write GIMPLE bytecode for link-time optimization. +Variable +int flag_relink_whthout_lto = 0 + ; Nonzero if we should write GIMPLE bytecode for offload compilation. Variable int flag_generate_offload = 0 @@ -2161,6 +2165,10 @@ flto Common Enable link-time optimization. +flto-try +Common Var(flag_lto_try) Init(0) +Do link-time optimization as much as possible. + flto= Common RejectNegative Joined Var(flag_lto) Link-time optimization with number of parallel jobs or jobserver. diff --git a/gcc/opts-common.cc b/gcc/opts-common.cc index 33c696f3d..176041bfe 100644 --- a/gcc/opts-common.cc +++ b/gcc/opts-common.cc @@ -1162,7 +1162,50 @@ decode_cmdline_options_to_array (unsigned int argc, const char **argv, struct cl_decoded_option *opt_array; unsigned int num_decoded_options; - int opt_array_len = argc; + enum LTO_SKIP_STAT + { + NO_NEED_TO_SKIP, + NEED_TO_SKIP, + ALREADY_SKIP, + }; + LTO_SKIP_STAT lto_skip_stat = NO_NEED_TO_SKIP; + bool try_use_lto = false; + const char* lto_option_conflict = NULL; + const char* wrap_option = "-Wl,--wrap="; + const char* start_lib_option = "-Wl,--start-lib"; + for (i = 1; i < argc; i += 1) + { + if (startswith (argv[i], "-flto-try")) + { + try_use_lto = true; + } + + if (startswith (argv[i], wrap_option) + && (lto_skip_stat == NO_NEED_TO_SKIP)) + { + lto_option_conflict = wrap_option; + lto_skip_stat = NEED_TO_SKIP; + } + else if (startswith (argv[i], start_lib_option) + && (lto_skip_stat == NO_NEED_TO_SKIP)) + { + lto_option_conflict = start_lib_option; + lto_skip_stat = NEED_TO_SKIP; + } + else if (startswith (argv[i], "-fno-lto")) + { + lto_option_conflict = NULL; + lto_skip_stat = ALREADY_SKIP; + break; + } + } + if (!try_use_lto) + { + lto_skip_stat = NO_NEED_TO_SKIP; + lto_option_conflict = NULL; + } + + int opt_array_len = lto_skip_stat == NEED_TO_SKIP ? argc + 1 : argc; opt_array = XNEWVEC (struct cl_decoded_option, opt_array_len); opt_array[0].opt_index = OPT_SPECIAL_program_name; @@ -1244,6 +1287,15 @@ decode_cmdline_options_to_array (unsigned int argc, const char **argv, num_decoded_options += handle_machine_option (lang_mask, num_decoded_options, argc, argv, opt_array); + if (lto_skip_stat == NEED_TO_SKIP) + { + const char * nolto = "-fno-lto"; + fprintf (stderr, "skip lto for %s\n", lto_option_conflict); + decode_cmdline_option (&nolto, lang_mask, + &opt_array[num_decoded_options]); + num_decoded_options++; + } + *decoded_options = opt_array; *decoded_options_count = num_decoded_options; prune_options (decoded_options, decoded_options_count, lang_mask); diff --git a/gcc/opts.cc b/gcc/opts.cc index 84dd8925a..9ccc22510 100644 --- a/gcc/opts.cc +++ b/gcc/opts.cc @@ -1143,6 +1143,26 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set, SET_OPTION_IF_UNSET (opts, opts_set, param_stack_frame_growth, 40); } + if (opts->x_flag_lto_try) + { +#ifdef ENABLE_LTO + if (opts_set->x_flag_lto && opts->x_flag_lto) + { + inform (loc, "%<-flto-try%> don't guarantee that lto " + "will be enabled."); + } + opts->x_flag_lto = ""; + if (opts_set->x_flag_fat_lto_objects && !opts->x_flag_fat_lto_objects) + { + error_at (loc, "%<-flto-try%> are not supported with " + "-fno-fat-lto-objects"); + } + opts->x_flag_fat_lto_objects = 1; +#else + error_at (loc, "LTO support has not been enabled in this configuration"); +#endif + } + if (opts->x_flag_lto) { #ifdef ENABLE_LTO -- 2.33.0