Hi, here is the patch that implement incremental LTO linking. I will wait few days for feedback. gcc -r now does LTO IL linking only. To force codegen, one can use -Wl,-rnolto which I found no right place to document. We may want -rnolto flag uspported by GCC driver, so the testsuite can be updated to use -rnolto whenever it uses -r currently and it won't fail on unrecognized option with non-GNU linkers. I got lost in gcc.c and I do not know where -rdynamic is parsed (I suppose at the same spot I can do -rnolto and turn it into -r -Wl,-rnolto on plugin enabled setups and -r on others)
There are still few bugs to track. Most notably WPA will produce hidden symbols with non-obstructated names which may conflict with later static linking. I will look into that separately and also try to find more testcases. * lto-streamer-out.c: Also copy sections when flag_incremental_link == 2 * flag-types.h (lto_partition_model): Add LTO_LINKER_OUTPUT_NOLTOREL. * common.opt (flag_incremental_link): Update docs. * passes.c (ipa_write_summaries): Only renumber statements when the body is really in memory. * lto-wrapper.c (run_gcc): Parse -flinker-output and turn into non-WPA mode at -flinker-output=rel. * lang.opt (lto_linker_output): New value noltorel. * lto-lang.c (lto_post_options): Handle LTO_LINKER_OUTPUT_REL and LTO_LINKER_OUTPUT_NOLTOREL. (lto_init): We also generate LTO during incremental_link. * toplev.c (compile_file): Cut compilation when doing incremental link. * cgraphunit.c (ipa_passes): Support incremental link. (symbol_table::compile): Likewise. * lto-cgraph.c (lto_output_node): Do not propagate resolution info when linking incrmentally. * lto-plugin.c: Document flags; add new flag -rnolto (non_claimed_files, rnolto): New statics. (all_symbols_read_handler): Decide on rel model. (claim_file_handler): Count non_claimed_files (process_option): Process rnolto. Index: gcc/lto-streamer-out.c =================================================================== --- gcc/lto-streamer-out.c (revision 230915) +++ gcc/lto-streamer-out.c (working copy) @@ -2286,13 +2286,16 @@ lto_output (void) } decl_state = lto_new_out_decl_state (); lto_push_out_decl_state (decl_state); - if (gimple_has_body_p (node->decl) || !flag_wpa + if (gimple_has_body_p (node->decl) /* Thunks have no body but they may be synthetized at WPA time. */ || DECL_ARGUMENTS (node->decl)) output_function (node); else - copy_function_or_variable (node); + { + gcc_checking_assert (flag_wpa || flag_incremental_link == 2); + copy_function_or_variable (node); + } gcc_assert (lto_get_out_decl_state () == decl_state); lto_pop_out_decl_state (); lto_record_function_out_decl_state (node->decl, decl_state); @@ -2318,7 +2321,7 @@ lto_output (void) decl_state = lto_new_out_decl_state (); lto_push_out_decl_state (decl_state); if (DECL_INITIAL (node->decl) != error_mark_node - || !flag_wpa) + || (!flag_wpa && flag_incremental_link != 2)) output_constructor (node); else copy_function_or_variable (node); Index: gcc/flag-types.h =================================================================== --- gcc/flag-types.h (revision 230915) +++ gcc/flag-types.h (working copy) @@ -269,6 +269,7 @@ enum lto_partition_model { enum lto_linker_output { LTO_LINKER_OUTPUT_UNKNOWN, LTO_LINKER_OUTPUT_REL, + LTO_LINKER_OUTPUT_NOLTOREL, LTO_LINKER_OUTPUT_DYN, LTO_LINKER_OUTPUT_PIE, LTO_LINKER_OUTPUT_EXEC Index: gcc/common.opt =================================================================== --- gcc/common.opt (revision 230915) +++ gcc/common.opt (working copy) @@ -48,7 +48,8 @@ bool in_lto_p = false ; This variable is set to non-0 only by LTO front-end. 1 indicates that ; the output produced will be used for incrmeental linking (thus weak symbols -; can still be bound). +; can still be bound) and 2 indicates that the IL is going to be linked and +; and output to LTO object file. Variable int flag_incremental_link = 0 Index: gcc/passes.c =================================================================== --- gcc/passes.c (revision 230915) +++ gcc/passes.c (working copy) @@ -2530,7 +2530,7 @@ ipa_write_summaries (void) { struct cgraph_node *node = order[i]; - if (node->has_gimple_body_p ()) + if (gimple_has_body_p (node->decl)) { /* When streaming out references to statements as part of some IPA pass summary, the statements need to have uids assigned and the Index: gcc/lto-wrapper.c =================================================================== --- gcc/lto-wrapper.c (revision 230915) +++ gcc/lto-wrapper.c (working copy) @@ -953,9 +953,15 @@ run_gcc (unsigned argc, char *argv[]) file_offset = (off_t) loffset; } fd = open (filename, O_RDONLY | O_BINARY); + /* Linker plugin passes -fresolution and -flinker-output options. */ if (fd == -1) { lto_argv[lto_argc++] = argv[i]; + if (strcmp (argv[i], "-flinker-output=rel") == 0) + { + no_partition = true; + lto_mode = LTO_MODE_LTO; + } continue; } Index: gcc/lto/lang.opt =================================================================== --- gcc/lto/lang.opt (revision 230915) +++ gcc/lto/lang.opt (working copy) @@ -34,6 +34,9 @@ EnumValue Enum(lto_linker_output) String(rel) Value(LTO_LINKER_OUTPUT_REL) EnumValue +Enum(lto_linker_output) String(noltorel) Value(LTO_LINKER_OUTPUT_NOLTOREL) + +EnumValue Enum(lto_linker_output) String(dyn) Value(LTO_LINKER_OUTPUT_DYN) EnumValue Index: gcc/lto/lto-lang.c =================================================================== --- gcc/lto/lto-lang.c (revision 230915) +++ gcc/lto/lto-lang.c (working copy) @@ -823,6 +823,26 @@ lto_post_options (const char **pfilename switch (flag_lto_linker_output) { case LTO_LINKER_OUTPUT_REL: /* .o: incremental link producing LTO IL */ + /* Configure compiler same way as normal frontend would do with -flto: + this way we read the trees (declarations & types), symbol table, + optimization summaries and link them. Subsequently we output new LTO + file. */ + flag_lto = ""; + flag_incremental_link = 2; + flag_whole_program = 0; + flag_wpa = 0; + flag_generate_lto = 1; + /* It would be cool to produce .o file directly, but our current + simple objects does not contain the lto symbol markers. Go the slow + way through the asm file. */ + lang_hooks.lto.begin_section = lhd_begin_section; + lang_hooks.lto.append_data = lhd_append_data; + lang_hooks.lto.end_section = lhd_end_section; + if (flag_ltrans) + error ("-flinker-output=rel and -fltrans are mutually exclussive"); + break; + + case LTO_LINKER_OUTPUT_NOLTOREL: /* .o: incremental link producing asm */ flag_whole_program = 0; flag_incremental_link = 1; break; @@ -1243,7 +1263,7 @@ lto_init (void) int i; /* We need to generate LTO if running in WPA mode. */ - flag_generate_lto = (flag_wpa != NULL); + flag_generate_lto = (flag_incremental_link == 2 || flag_wpa != NULL); /* Create the basic integer types. */ build_common_tree_nodes (flag_signed_char, flag_short_double); Index: gcc/toplev.c =================================================================== --- gcc/toplev.c (revision 230915) +++ gcc/toplev.c (working copy) @@ -504,7 +504,8 @@ compile_file (void) /* Compilation unit is finalized. When producing non-fat LTO object, we are basically finished. */ - if (in_lto_p || !flag_lto || flag_fat_lto_objects) + if ((in_lto_p && flag_incremental_link != 2) + || !flag_lto || flag_fat_lto_objects) { /* File-scope initialization for AddressSanitizer. */ if (flag_sanitize & SANITIZE_ADDRESS) Index: gcc/cgraphunit.c =================================================================== --- gcc/cgraphunit.c (revision 230915) +++ gcc/cgraphunit.c (working copy) @@ -2270,8 +2270,10 @@ ipa_passes (void) if (flag_generate_lto || flag_generate_offload) targetm.asm_out.lto_start (); - if (!in_lto_p) + if (!in_lto_p || flag_incremental_link == 2) { + if (!quiet_flag) + fprintf (stderr, "Streaming LTO\n"); if (g->have_offload) { section_name_prefix = OFFLOAD_SECTION_NAME_PREFIX; @@ -2290,7 +2292,9 @@ ipa_passes (void) if (flag_generate_lto || flag_generate_offload) targetm.asm_out.lto_end (); - if (!flag_ltrans && (in_lto_p || !flag_lto || flag_fat_lto_objects)) + if (!flag_ltrans + && ((in_lto_p && flag_incremental_link != 2) + || !flag_lto || flag_fat_lto_objects)) execute_ipa_pass_list (passes->all_regular_ipa_passes); invoke_plugin_callbacks (PLUGIN_ALL_IPA_PASSES_END, NULL); @@ -2381,7 +2385,8 @@ symbol_table::compile (void) /* Do nothing else if any IPA pass found errors or if we are just streaming LTO. */ if (seen_error () - || (!in_lto_p && flag_lto && !flag_fat_lto_objects)) + || ((!in_lto_p || flag_incremental_link == 2) + && flag_lto && !flag_fat_lto_objects)) { timevar_pop (TV_CGRAPHOPT); return; Index: gcc/lto-cgraph.c =================================================================== --- gcc/lto-cgraph.c (revision 230915) +++ gcc/lto-cgraph.c (working copy) @@ -534,7 +534,10 @@ lto_output_node (struct lto_simple_outpu bp_pack_value (&bp, node->thunk.thunk_p, 1); bp_pack_value (&bp, node->parallelized_function, 1); bp_pack_enum (&bp, ld_plugin_symbol_resolution, - LDPR_NUM_KNOWN, node->resolution); + LDPR_NUM_KNOWN, + /* When doing incremental link, we will get new resolution + info next time we process the file. */ + flag_incremental_link ? LDPR_UNKNOWN : node->resolution); bp_pack_value (&bp, node->instrumentation_clone, 1); bp_pack_value (&bp, node->split_part, 1); streamer_write_bitpack (&bp); Index: lto-plugin/lto-plugin.c =================================================================== --- lto-plugin/lto-plugin.c (revision 230915) +++ lto-plugin/lto-plugin.c (working copy) @@ -27,10 +27,13 @@ along with this program; see the file CO More information at http://gcc.gnu.org/wiki/whopr/driver. This plugin should be passed the lto-wrapper options and will forward them. - It also has 2 options of its own: + It also has options at his own: -debug: Print the command line used to run lto-wrapper. -nop: Instead of running lto-wrapper, pass the original to the plugin. This - only works if the input files are hybrid. */ + only works if the input files are hybrid. + -rnolto: When doing incremental linking, turn the result into actual binary + -sym-style={none,win32,underscore|uscore} + -pass-through */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -151,6 +154,7 @@ static ld_plugin_add_symbols add_symbols static struct plugin_file_info *claimed_files = NULL; static unsigned int num_claimed_files = 0; +static unsigned int non_claimed_files = 0; static struct plugin_file_info *offload_files = NULL; static unsigned int num_offload_files = 0; @@ -169,6 +173,7 @@ static char nop; static char *resolution_file = NULL; static enum ld_plugin_output_file_type linker_output; static int linker_output_set; +static int rnolto; /* The version of gold being used, or -1 if not gold. The number is MAJOR * 100 + MINOR. */ @@ -655,7 +660,17 @@ all_symbols_read_handler (void) switch (linker_output) { case LDPO_REL: - linker_output_str = "-flinker-output=rel"; + if (non_claimed_files) + { + rnolto = 1; + message (LDPL_WARNING, "incremental linking of LTO and non-LTO " + "objects will produce final assembly for LTO objects and " + "bypass whole program optimization"); + } + if (rnolto) + linker_output_str = "-flinker-output=nonltorel"; + else + linker_output_str = "-flinker-output=rel"; break; case LDPO_DYN: linker_output_str = "-flinker-output=dyn"; @@ -1008,6 +1023,8 @@ claim_file_handler (const struct ld_plug num_claimed_files * sizeof (struct plugin_file_info)); claimed_files[num_claimed_files - 1] = lto_file; } + else + non_claimed_files++; if (obj.found == 0 && obj.offload == 1) { @@ -1037,6 +1054,8 @@ claim_file_handler (const struct ld_plug static void process_option (const char *option) { + if (strcmp (option, "-rnolto") == 0) + rnolto = 1; if (strcmp (option, "-debug") == 0) debug = 1; else if (strcmp (option, "-nop") == 0)