Hi, this patch adds the symtab support for LTO incremental linking. Most of the code path is same for both modes of incremental link except hat we want to produce LTO object file rather than compile down to assembly.
Only non-obvious changes are in ipa.c where I hit a bug where we stream in initializers that are going to be eliminated form the symbol table for no good reasons. Bootstrapped/regtested x86_64-linux with rest of the incremental link patchset. Honza * passes.c (ipa_write_summaries): Only modify statements if body is in memory. * cgraphunit.c (ipa_passes): Also produce intermeidate code when incrementally linking. (ipa_passes): Likewise. * lto-cgraph.c (lto_output_node): When incrementally linking do not pass down resolution info. * common.opt (flag_incremental_link): Update info. * gcc.c (plugin specs): Turn flinker-output=* to -plugin-opt=-linker-output-known * toplev.c (compile_file): Also cut compilation when doing incremental link. * flag-types. (enum lto_partition_model): Add LTO_LINKER_OUTPUT_NOLTOREL. (invoke.texi): Add -flinker-output docs. * ipa.c (symbol_table::remove_unreachable_nodes): Handle LTO incremental link same way as WPA; do not stream in dead initializers. * lang.opt (lto_linker_output): Add nolto-rel. * lto-lang.c (lto_post_options): Handle LTO_LINKER_OUTPUT_REL and LTO_LINKER_OUTPUT_NOLTOREL. (lto_init): Generate lto when doing incremental link. * lto.c (lto_precess_name): Add lto1-inclink. Index: cgraphunit.c =================================================================== --- cgraphunit.c (revision 260042) +++ cgraphunit.c (working copy) @@ -2452,8 +2452,10 @@ 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; @@ -2472,7 +2474,9 @@ 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); @@ -2559,7 +2563,8 @@ /* 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: common.opt =================================================================== --- common.opt (revision 260042) +++ common.opt (working copy) @@ -48,7 +48,8 @@ ; 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: flag-types.h =================================================================== --- flag-types.h (revision 260042) +++ flag-types.h (working copy) @@ -289,6 +289,7 @@ 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.c =================================================================== --- gcc.c (revision 260042) +++ gcc.c (working copy) @@ -961,6 +961,7 @@ -plugin %(linker_plugin_file) \ -plugin-opt=%(lto_wrapper) \ -plugin-opt=-fresolution=%u.res \ + %{flinker-output=*:-plugin-opt=-linker-output-known} \ %{!nostdlib:%{!nodefaultlibs:%:pass-through-libs(%(link_gcc_c_sequence))}} \ }" PLUGIN_COND_CLOSE #else Index: ipa.c =================================================================== --- ipa.c (revision 260042) +++ ipa.c (working copy) @@ -130,9 +130,9 @@ constant folding. Keep references alive so partitioning knows about potential references. */ || (VAR_P (node->decl) - && flag_wpa - && ctor_for_folding (node->decl) - != error_mark_node)))) + && (flag_wpa || flag_incremental_link == 2) + && dyn_cast <varpool_node *> (node) + ->ctor_useable_for_folding_p ())))) { /* Be sure that we will not optimize out alias target body. */ @@ -622,7 +622,7 @@ fprintf (file, " %s", vnode->dump_name ()); vnext = next_variable (vnode); /* Signal removal to the debug machinery. */ - if (! flag_wpa) + if (! flag_wpa || flag_incremental_link == 2) { vnode->definition = false; (*debug_hooks->late_global_decl) (vnode->decl); @@ -640,8 +640,9 @@ changed = true; } /* Keep body if it may be useful for constant folding. */ - if ((init = ctor_for_folding (vnode->decl)) == error_mark_node - && !POINTER_BOUNDS_P (vnode->decl)) + if ((flag_wpa || flag_incremental_link == 2) + || ((init = ctor_for_folding (vnode->decl)) == error_mark_node + && !POINTER_BOUNDS_P (vnode->decl))) vnode->remove_initializer (); else DECL_INITIAL (vnode->decl) = init; Index: lto/lang.opt =================================================================== --- lto/lang.opt (revision 260042) +++ lto/lang.opt (working copy) @@ -34,6 +34,9 @@ Enum(lto_linker_output) String(rel) Value(LTO_LINKER_OUTPUT_REL) EnumValue +Enum(lto_linker_output) String(nolto-rel) Value(LTO_LINKER_OUTPUT_NOLTOREL) + +EnumValue Enum(lto_linker_output) String(dyn) Value(LTO_LINKER_OUTPUT_DYN) EnumValue Index: lto/lto-lang.c =================================================================== --- lto/lto-lang.c (revision 260042) +++ lto/lto-lang.c (working copy) @@ -879,7 +879,27 @@ 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; @@ -1269,7 +1289,7 @@ in_lto_p = true; /* 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); Index: lto/lto.c =================================================================== --- lto/lto.c (revision 260042) +++ lto/lto.c (working copy) @@ -3257,7 +3257,7 @@ lto_process_name (void) { if (flag_lto) - setproctitle ("lto1-lto"); + setproctitle (flag_incremental_link == 2 ? "lto1-inclink" : "lto1-lto"); if (flag_wpa) setproctitle ("lto1-wpa"); if (flag_ltrans) Index: lto-cgraph.c =================================================================== --- lto-cgraph.c (revision 260042) +++ lto-cgraph.c (working copy) @@ -540,7 +540,10 @@ 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-streamer-out.c =================================================================== --- lto-streamer-out.c (revision 260042) +++ lto-streamer-out.c (working copy) @@ -2406,7 +2406,8 @@ } 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) + || (!flag_wpa && flag_incremental_link != 2) /* Thunks have no body but they may be synthetized at WPA time. */ || DECL_ARGUMENTS (node->decl)) @@ -2438,7 +2439,7 @@ 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: passes.c =================================================================== --- passes.c (revision 260042) +++ passes.c (working copy) @@ -2708,7 +2708,7 @@ { 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: toplev.c =================================================================== --- toplev.c (revision 260042) +++ toplev.c (working copy) @@ -495,7 +495,8 @@ /* 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)