This adds loop tree streaming to LTO. LTO bootstrapped and tested on x86_64-unknown-linux-gnu, applied.
Richard. 2013-04-26 Richard Biener <rguent...@suse.de> * Makefile.in (lto-streamer-in.o): Add $(CFGLOOP_H) dependency. (lto-streamer-out.o): Likewise. * cfgloop.c (init_loops_structure): Export, add struct function argument and adjust. (flow_loops_find): Adjust. * cfgloop.h (enum loop_estimation): Add EST_LAST. (init_loops_structure): Declare. * lto-streamer-in.c: Include cfgloop.h. (input_cfg): Input the loop tree. * lto-streamer-out.c: Include cfgloop.h. (output_cfg): Output the loop tree. (output_struct_function_base): Do not drop PROP_loops. Index: trunk/gcc/Makefile.in =================================================================== *** trunk.orig/gcc/Makefile.in 2013-04-26 10:01:45.000000000 +0200 --- trunk/gcc/Makefile.in 2013-04-26 10:36:17.494133278 +0200 *************** lto-streamer-in.o: lto-streamer-in.c $(C *** 2174,2184 **** $(TM_H) toplev.h $(DIAGNOSTIC_CORE_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) \ input.h $(HASHTAB_H) $(BASIC_BLOCK_H) $(TREE_FLOW_H) $(TREE_PASS_H) \ $(CGRAPH_H) $(FUNCTION_H) $(GGC_H) $(DIAGNOSTIC_H) $(EXCEPT_H) debug.h \ ! $(IPA_UTILS_H) $(LTO_STREAMER_H) toplev.h \ $(DATA_STREAMER_H) $(GIMPLE_STREAMER_H) $(TREE_STREAMER_H) lto-streamer-out.o : lto-streamer-out.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TM_H) $(DIAGNOSTIC_CORE_H) $(TREE_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h \ ! $(HASHTAB_H) $(BASIC_BLOCK_H) tree-iterator.h \ $(TREE_FLOW_H) $(TREE_PASS_H) $(CGRAPH_H) $(FUNCTION_H) $(GGC_H) \ $(DIAGNOSTIC_CORE_H) $(EXCEPT_H) $(LTO_STREAMER_H) $(DIAGNOSTIC_CORE_H) \ $(DATA_STREAMER_H) $(STREAMER_HOOKS_H) $(GIMPLE_STREAMER_H) \ --- 2174,2184 ---- $(TM_H) toplev.h $(DIAGNOSTIC_CORE_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) \ input.h $(HASHTAB_H) $(BASIC_BLOCK_H) $(TREE_FLOW_H) $(TREE_PASS_H) \ $(CGRAPH_H) $(FUNCTION_H) $(GGC_H) $(DIAGNOSTIC_H) $(EXCEPT_H) debug.h \ ! $(IPA_UTILS_H) $(LTO_STREAMER_H) toplev.h $(CFGLOOP_H) \ $(DATA_STREAMER_H) $(GIMPLE_STREAMER_H) $(TREE_STREAMER_H) lto-streamer-out.o : lto-streamer-out.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TM_H) $(DIAGNOSTIC_CORE_H) $(TREE_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h \ ! $(HASHTAB_H) $(BASIC_BLOCK_H) tree-iterator.h $(CFGLOOP_H) \ $(TREE_FLOW_H) $(TREE_PASS_H) $(CGRAPH_H) $(FUNCTION_H) $(GGC_H) \ $(DIAGNOSTIC_CORE_H) $(EXCEPT_H) $(LTO_STREAMER_H) $(DIAGNOSTIC_CORE_H) \ $(DATA_STREAMER_H) $(STREAMER_HOOKS_H) $(GIMPLE_STREAMER_H) \ Index: trunk/gcc/cfgloop.c =================================================================== *** trunk.orig/gcc/cfgloop.c 2013-04-26 10:01:45.000000000 +0200 --- trunk/gcc/cfgloop.c 2013-04-26 10:38:35.297698554 +0200 *************** alloc_loop (void) *** 339,346 **** /* Initializes loops structure LOOPS, reserving place for NUM_LOOPS loops (including the root of the loop tree). */ ! static void ! init_loops_structure (struct loops *loops, unsigned num_loops) { struct loop *root; --- 339,347 ---- /* Initializes loops structure LOOPS, reserving place for NUM_LOOPS loops (including the root of the loop tree). */ ! void ! init_loops_structure (struct function *fn, ! struct loops *loops, unsigned num_loops) { struct loop *root; *************** init_loops_structure (struct loops *loop *** 349,359 **** /* Dummy loop containing whole function. */ root = alloc_loop (); ! root->num_nodes = n_basic_blocks; ! root->latch = EXIT_BLOCK_PTR; ! root->header = ENTRY_BLOCK_PTR; ! ENTRY_BLOCK_PTR->loop_father = root; ! EXIT_BLOCK_PTR->loop_father = root; loops->larray->quick_push (root); loops->tree_root = root; --- 350,360 ---- /* Dummy loop containing whole function. */ root = alloc_loop (); ! root->num_nodes = n_basic_blocks_for_function (fn); ! root->latch = EXIT_BLOCK_PTR_FOR_FUNCTION (fn); ! root->header = ENTRY_BLOCK_PTR_FOR_FUNCTION (fn); ! ENTRY_BLOCK_PTR_FOR_FUNCTION (fn)->loop_father = root; ! EXIT_BLOCK_PTR_FOR_FUNCTION (fn)->loop_father = root; loops->larray->quick_push (root); loops->tree_root = root; *************** flow_loops_find (struct loops *loops) *** 411,417 **** if (!loops) { loops = ggc_alloc_cleared_loops (); ! init_loops_structure (loops, 1); } /* Ensure that loop exits were released. */ --- 412,418 ---- if (!loops) { loops = ggc_alloc_cleared_loops (); ! init_loops_structure (cfun, loops, 1); } /* Ensure that loop exits were released. */ Index: trunk/gcc/cfgloop.h =================================================================== *** trunk.orig/gcc/cfgloop.h 2013-04-26 10:01:45.000000000 +0200 --- trunk/gcc/cfgloop.h 2013-04-26 10:41:45.600861044 +0200 *************** enum loop_estimation *** 97,103 **** /* Estimate was not computed yet. */ EST_NOT_COMPUTED, /* Estimate is ready. */ ! EST_AVAILABLE }; /* Structure to hold information for each natural loop. */ --- 97,104 ---- /* Estimate was not computed yet. */ EST_NOT_COMPUTED, /* Estimate is ready. */ ! EST_AVAILABLE, ! EST_LAST }; /* Structure to hold information for each natural loop. */ *************** struct GTY (()) loops { *** 213,218 **** --- 214,220 ---- /* Loop recognition. */ bool bb_loop_header_p (basic_block); + void init_loops_structure (struct function *, struct loops *, unsigned); extern struct loops *flow_loops_find (struct loops *); extern void disambiguate_loops_with_multiple_latches (void); extern void flow_loops_free (struct loops *); Index: trunk/gcc/lto-streamer-in.c =================================================================== *** trunk.orig/gcc/lto-streamer-in.c 2013-04-26 09:55:31.000000000 +0200 --- trunk/gcc/lto-streamer-in.c 2013-04-26 10:51:15.734333125 +0200 *************** along with GCC; see the file COPYING3. *** 48,53 **** --- 48,55 ---- #include "tree-streamer.h" #include "tree-pass.h" #include "streamer-hooks.h" + #include "cfgloop.h" + struct freeing_string_slot_hasher : string_slot_hasher { *************** input_cfg (struct lto_input_block *ib, s *** 660,665 **** --- 662,719 ---- p_bb = bb; index = streamer_read_hwi (ib); } + + /* ??? The cfgloop interface is tied to cfun. */ + gcc_assert (cfun == fn); + + /* Input the loop tree. */ + unsigned n_loops = streamer_read_uhwi (ib); + if (n_loops == 0) + return; + + struct loops *loops = ggc_alloc_cleared_loops (); + init_loops_structure (fn, loops, n_loops); + + /* Input each loop and associate it with its loop header so + flow_loops_find can rebuild the loop tree. */ + for (unsigned i = 1; i < n_loops; ++i) + { + int header_index = streamer_read_hwi (ib); + if (header_index == -1) + { + loops->larray->quick_push (NULL); + continue; + } + + struct loop *loop = alloc_loop (); + loop->num = loops->larray->length (); + loop->header = BASIC_BLOCK_FOR_FUNCTION (fn, header_index); + loop->header->loop_father = loop; + + /* Read everything copy_loop_info copies. */ + loop->estimate_state = streamer_read_enum (ib, loop_estimation, EST_LAST); + loop->any_upper_bound = streamer_read_hwi (ib); + if (loop->any_upper_bound) + { + loop->nb_iterations_upper_bound.low = streamer_read_uhwi (ib); + loop->nb_iterations_upper_bound.high = streamer_read_hwi (ib); + } + loop->any_estimate = streamer_read_hwi (ib); + if (loop->any_estimate) + { + loop->nb_iterations_estimate.low = streamer_read_uhwi (ib); + loop->nb_iterations_estimate.high = streamer_read_hwi (ib); + } + + loops->larray->quick_push (loop); + + /* flow_loops_find doesn't like loops not in the tree, hook them + all as siblings of the tree root temporarily. */ + flow_loop_tree_node_add (loops->tree_root, loop); + } + + /* Rebuild the loop tree. */ + fn->x_current_loops = flow_loops_find (loops); } Index: trunk/gcc/lto-streamer-out.c =================================================================== *** trunk.orig/gcc/lto-streamer-out.c 2013-04-26 10:01:45.000000000 +0200 --- trunk/gcc/lto-streamer-out.c 2013-04-26 10:47:58.027089845 +0200 *************** along with GCC; see the file COPYING3. *** 45,50 **** --- 45,51 ---- #include "gimple-streamer.h" #include "tree-streamer.h" #include "streamer-hooks.h" + #include "cfgloop.h" /* Clear the line info stored in DATA_IN. */ *************** output_cfg (struct output_block *ob, str *** 659,664 **** --- 660,704 ---- streamer_write_hwi (ob, -1); + /* ??? The cfgloop interface is tied to cfun. */ + gcc_assert (cfun == fn); + + /* Output the number of loops. */ + streamer_write_uhwi (ob, number_of_loops ()); + + /* Output each loop, skipping the tree root which has number zero. */ + for (unsigned i = 1; i < number_of_loops (); ++i) + { + struct loop *loop = get_loop (i); + + /* Write the index of the loop header. That's enough to rebuild + the loop tree on the reader side. Stream -1 for an unused + loop entry. */ + if (!loop) + { + streamer_write_hwi (ob, -1); + continue; + } + else + streamer_write_hwi (ob, loop->header->index); + + /* Write everything copy_loop_info copies. */ + streamer_write_enum (ob->main_stream, + loop_estimation, EST_LAST, loop->estimate_state); + streamer_write_hwi (ob, loop->any_upper_bound); + if (loop->any_upper_bound) + { + streamer_write_uhwi (ob, loop->nb_iterations_upper_bound.low); + streamer_write_hwi (ob, loop->nb_iterations_upper_bound.high); + } + streamer_write_hwi (ob, loop->any_estimate); + if (loop->any_estimate) + { + streamer_write_uhwi (ob, loop->nb_iterations_estimate.low); + streamer_write_hwi (ob, loop->nb_iterations_estimate.high); + } + } + ob->main_stream = tmp_stream; } *************** output_struct_function_base (struct outp *** 733,741 **** FOR_EACH_VEC_SAFE_ELT (fn->local_decls, i, t) stream_write_tree (ob, t, true); ! /* Output current IL state of the function. ! ??? We don't stream loops. */ ! streamer_write_uhwi (ob, fn->curr_properties & ~PROP_loops); /* Write all the attributes for FN. */ bp = bitpack_create (ob->main_stream); --- 773,780 ---- FOR_EACH_VEC_SAFE_ELT (fn->local_decls, i, t) stream_write_tree (ob, t, true); ! /* Output current IL state of the function. */ ! streamer_write_uhwi (ob, fn->curr_properties); /* Write all the attributes for FN. */ bp = bitpack_create (ob->main_stream);