Hello, as discussed in http://gcc.gnu.org/ml/gcc-patches/2007-05/msg01133.html, it might be a good idea to try moving cfg to alloc pools. The patch below does that for basic blocks (each function has a separate pool from that its basic blocks are allocated). At the moment, the patch breaks precompiled headers, but otherwise bootstraps and passes regtesting.
The problem is, that it does not give any speedups (it is almost completely compile-time neutral for compilation of preprocessed gcc sources). I will check whether moving also edges to pools changes anything, but so far it does not seem very promising :-( Zdenek Index: doc/gty.texi =================================================================== *** doc/gty.texi (revision 125526) --- doc/gty.texi (working copy) *************** reachable. This routine should not chang *** 292,297 **** --- 292,304 ---- routine. Its only argument is a pointer to the just marked (const) structure or union. + @findex custom_mark + @item custom_mark ("@var{marking-routine-name}") + + If provided for a structure or union type, the given + @var{marking-routine-name} (between double-quotes) is the name of a + routine called to mark the object instead of ggc_set_mark. + @findex maybe_undef @item maybe_undef Index: gengtype.c =================================================================== *** gengtype.c (revision 125526) --- gengtype.c (working copy) *************** walk_type (type_p t, struct walk_type_da *** 1916,1921 **** --- 1916,1923 ---- desc = oo->info; else if (strcmp (oo->name, "mark_hook") == 0) ; + else if (strcmp (oo->name, "custom_mark") == 0) + ; else if (strcmp (oo->name, "nested_ptr") == 0) nested_ptr_d = (const struct nested_ptr_data *) oo->info; else if (strcmp (oo->name, "dot") == 0) *************** write_func_for_structure (type_p orig_s, *** 2418,2423 **** --- 2420,2426 ---- const char *chain_next = NULL; const char *chain_prev = NULL; const char *mark_hook_name = NULL; + const char *marker_routine = wtd->marker_routine; options_p opt; struct walk_type_data d; *************** write_func_for_structure (type_p orig_s, *** 2437,2442 **** --- 2440,2449 ---- chain_prev = opt->info; else if (strcmp (opt->name, "mark_hook") == 0) mark_hook_name = opt->info; + else if (strcmp (opt->name, "custom_mark") == 0 + /* FIXME -- this will break pch. */ + && !wtd->param_prefix) + marker_routine = opt->info; if (chain_prev != NULL && chain_next == NULL) error_at_line (&s->u.s.line, "chain_prev without chain_next"); *************** write_func_for_structure (type_p orig_s, *** 2473,2479 **** s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag); if (chain_next == NULL) { ! oprintf (d.of, " if (%s (x", wtd->marker_routine); if (wtd->param_prefix) { oprintf (d.of, ", x, gt_%s_", wtd->param_prefix); --- 2480,2486 ---- s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag); if (chain_next == NULL) { ! oprintf (d.of, " if (%s (x", marker_routine); if (wtd->param_prefix) { oprintf (d.of, ", x, gt_%s_", wtd->param_prefix); *************** write_func_for_structure (type_p orig_s, *** 2484,2490 **** } else { ! oprintf (d.of, " while (%s (xlimit", wtd->marker_routine); if (wtd->param_prefix) { oprintf (d.of, ", xlimit, gt_%s_", wtd->param_prefix); --- 2491,2497 ---- } else { ! oprintf (d.of, " while (%s (xlimit", marker_routine); if (wtd->param_prefix) { oprintf (d.of, ", xlimit, gt_%s_", wtd->param_prefix); *************** write_func_for_structure (type_p orig_s, *** 2516,2523 **** oprintf (d.of, ");\n"); oprintf (d.of, " if (xprev == NULL) break;\n"); oprintf (d.of, " x = xprev;\n"); ! oprintf (d.of, " (void) %s (xprev", ! wtd->marker_routine); if (wtd->param_prefix) { oprintf (d.of, ", xprev, gt_%s_", wtd->param_prefix); --- 2523,2529 ---- oprintf (d.of, ");\n"); oprintf (d.of, " if (xprev == NULL) break;\n"); oprintf (d.of, " x = xprev;\n"); ! oprintf (d.of, " (void) %s (xprev", marker_routine); if (wtd->param_prefix) { oprintf (d.of, ", xprev, gt_%s_", wtd->param_prefix); Index: final.c =================================================================== *** final.c (revision 125526) --- final.c (working copy) *************** rest_of_handle_final (void) *** 3996,4004 **** if (! quiet_flag) fflush (asm_out_file); - /* Release all memory allocated by flow. */ - free_basic_block_vars (); - /* Write DBX symbols if requested. */ /* Note that for those inline functions where we don't initially --- 3996,4001 ---- *************** rest_of_clean_state (void) *** 4112,4118 **** free_basic_block_vars (); free_bb_for_insn (); - if (targetm.binds_local_p (current_function_decl)) { int pref = cfun->preferred_stack_boundary; --- 4109,4114 ---- Index: omp-low.c =================================================================== *** omp-low.c (revision 125526) --- omp-low.c (working copy) *************** expand_omp_parallel (struct omp_region * *** 2510,2516 **** dominance information because the expansion of the inner regions has invalidated it. */ free_dominance_info (CDI_DOMINATORS); ! new_bb = move_sese_region_to_fn (child_cfun, entry_bb, exit_bb); if (exit_bb) single_succ_edge (new_bb)->flags = EDGE_FALLTHRU; DECL_STRUCT_FUNCTION (child_fn)->curr_properties --- 2510,2516 ---- dominance information because the expansion of the inner regions has invalidated it. */ free_dominance_info (CDI_DOMINATORS); ! new_bb = move_sese_region_to_fn (child_cfun, &entry_bb, &exit_bb); if (exit_bb) single_succ_edge (new_bb)->flags = EDGE_FALLTHRU; DECL_STRUCT_FUNCTION (child_fn)->curr_properties Index: cfg.c =================================================================== *** cfg.c (revision 125526) --- cfg.c (working copy) *************** Software Foundation, 51 Franklin Street, *** 28,34 **** Available functionality: - Initialization/deallocation ! init_flow, clear_edges - Low level basic block manipulation alloc_block, expunge_block - Edge manipulation --- 28,34 ---- Available functionality: - Initialization/deallocation ! init_flow, clear_edges, free_basic_block_vars - Low level basic block manipulation alloc_block, expunge_block - Edge manipulation *************** void *** 83,93 **** init_flow (void) { if (!cfun->cfg) ! cfun->cfg = GGC_CNEW (struct control_flow_graph); n_edges = 0; ! ENTRY_BLOCK_PTR = GGC_CNEW (struct basic_block_def); ENTRY_BLOCK_PTR->index = ENTRY_BLOCK; ! EXIT_BLOCK_PTR = GGC_CNEW (struct basic_block_def); EXIT_BLOCK_PTR->index = EXIT_BLOCK; ENTRY_BLOCK_PTR->next_bb = EXIT_BLOCK_PTR; EXIT_BLOCK_PTR->prev_bb = ENTRY_BLOCK_PTR; --- 83,106 ---- init_flow (void) { if (!cfun->cfg) ! { ! struct alloc_pool_gc_description *bb_pool_desc; ! ! cfun->cfg = GGC_CNEW (struct control_flow_graph); ! ! cfun->cfg->bb_pool = create_alloc_pool ("basic blocks", ! sizeof (struct basic_block_def), 100); ! bb_pool_desc = XNEW (struct alloc_pool_gc_description); ! bb_pool_desc->pool = cfun->cfg->bb_pool; ! bb_pool_desc->mark = gt_ggc_mx_basic_block_def; ! cfun->cfg->bb_pool_root = register_dynamic_root (alloc_pool_gc_root, ! bb_pool_desc); ! } ! n_edges = 0; ! ENTRY_BLOCK_PTR = alloc_block (); ENTRY_BLOCK_PTR->index = ENTRY_BLOCK; ! EXIT_BLOCK_PTR = alloc_block (); EXIT_BLOCK_PTR->index = EXIT_BLOCK; ENTRY_BLOCK_PTR->next_bb = EXIT_BLOCK_PTR; EXIT_BLOCK_PTR->prev_bb = ENTRY_BLOCK_PTR; *************** clear_edges (void) *** 127,140 **** gcc_assert (!n_edges); } /* Allocate memory for basic_block. */ basic_block alloc_block (void) { ! basic_block bb; ! bb = GGC_CNEW (struct basic_block_def); return bb; } --- 140,178 ---- gcc_assert (!n_edges); } + + /* Free the variables allocated by init_flow. */ + + void + free_basic_block_vars (void) + { + struct alloc_pool_gc_description *desc; + + if (basic_block_info) + { + clear_edges (); + basic_block_info = NULL; + } + n_basic_blocks = 0; + last_basic_block = 0; + n_edges = 0; + + desc = cfun->cfg->bb_pool_root->data; + unregister_dynamic_root (cfun->cfg->bb_pool_root); + free (desc); + free_alloc_pool (cfun->cfg->bb_pool); + + cfun->cfg = NULL; + } + /* Allocate memory for basic_block. */ basic_block alloc_block (void) { ! basic_block bb = pool_alloc (cfun->cfg->bb_pool); ! memset (bb, 0, sizeof (*bb)); return bb; } *************** expunge_block (basic_block b) *** 192,202 **** unlink_block (b); SET_BASIC_BLOCK (b->index, NULL); n_basic_blocks--; ! /* We should be able to ggc_free here, but we are not. ! The dead SSA_NAMES are left pointing to dead statements that are pointing ! to dead basic blocks making garbage collector to die. ! We should be able to release all dead SSA_NAMES and at the same time we should ! clear out BB pointer of dead statements consistently. */ } /* Connect E to E->src. */ --- 230,236 ---- unlink_block (b); SET_BASIC_BLOCK (b->index, NULL); n_basic_blocks--; ! pool_free (cfun->cfg->bb_pool, b); } /* Connect E to E->src. */ Index: flow.c =================================================================== *** flow.c (revision 125526) --- flow.c (working copy) *************** update_life_info_in_dirty_blocks (enum u *** 766,793 **** return retval; } - /* Free the variables allocated by find_basic_blocks. */ - - void - free_basic_block_vars (void) - { - if (basic_block_info) - { - clear_edges (); - basic_block_info = NULL; - } - n_basic_blocks = 0; - last_basic_block = 0; - n_edges = 0; - - label_to_block_map = NULL; - - ENTRY_BLOCK_PTR->aux = NULL; - ENTRY_BLOCK_PTR->il.rtl->global_live_at_end = NULL; - EXIT_BLOCK_PTR->aux = NULL; - EXIT_BLOCK_PTR->il.rtl->global_live_at_start = NULL; - } - /* Delete any insns that copy a register to itself. */ int --- 766,771 ---- Index: alloc-pool.c =================================================================== *** alloc-pool.c (revision 125526) --- alloc-pool.c (working copy) *************** Software Foundation, 51 Franklin Street, *** 24,29 **** --- 24,31 ---- #include "system.h" #include "alloc-pool.h" #include "hashtab.h" + #include "pointer-set.h" + #include "ggc.h" #define align_eight(x) (((x+7) >> 3) << 3) *************** create_alloc_pool (const char *name, siz *** 180,185 **** --- 182,226 ---- return (pool); } + /* Mark elements of pool described in struct alloc_pool_gc_description + as gc roots. */ + + void + alloc_pool_gc_root (void *data) + { + struct alloc_pool_gc_description *desc = data; + struct pointer_set_t *free_elts = pointer_set_create (); + alloc_pool_list elt, block_header; + char *block; + alloc_pool pool = desc->pool; + unsigned i; + + /* Find the allocated elements of the pool. This is somewhat tricky, as + we do not track those, but it suffices to traverse all elements of the + pool and ignore the free ones. */ + for (elt = pool->free_list; elt != NULL; elt = elt->next) + pointer_set_insert (free_elts, elt); + + for (block_header = pool->block_list; + block_header != NULL; + block_header = block_header->next) + { + block = (char *) block_header; + block += align_eight (sizeof (struct alloc_pool_list_def)); + + for (i = 0; i < pool->elts_per_block; i++, block += pool->elt_size) + { + elt = (alloc_pool_list) USER_PTR_FROM_ALLOCATION_OBJECT_PTR (block); + if (pointer_set_contains (free_elts, elt)) + continue; + + ggc_mark_dynamic_root (desc->mark, (void *) elt); + } + } + + pointer_set_destroy (free_elts); + } + /* Free all memory allocated for the given memory pool. */ void free_alloc_pool (alloc_pool pool) Index: alloc-pool.h =================================================================== *** alloc-pool.h (revision 125526) --- alloc-pool.h (working copy) *************** typedef struct alloc_pool_def *** 47,56 **** --- 47,69 ---- } *alloc_pool; + /* Description of the alloc pool for marking gc roots. */ + + struct alloc_pool_gc_description + { + /* The pool. */ + alloc_pool pool; + + /* The function used to traverse the elements of the pool. */ + void (*mark) (void *); + }; + extern alloc_pool create_alloc_pool (const char *, size_t, size_t); extern void free_alloc_pool (alloc_pool); extern void free_alloc_pool_if_empty (alloc_pool *); extern void *pool_alloc (alloc_pool); extern void pool_free (alloc_pool, void *); extern void dump_alloc_pool_statistics (void); + extern void alloc_pool_gc_root (void *); + #endif Index: ggc.h =================================================================== *** ggc.h (revision 125526) --- ggc.h (working copy) *************** extern void ggc_mark_stringpool (void); *** 125,130 **** --- 125,149 ---- extern void ggc_mark_roots (void); + /* Dynamic root management. */ + + struct dynamic_root + { + /* Double linked list of roots. */ + struct dynamic_root *prev, *next; + + /* Function called to mark the root. */ + void (*mark) (void *); + + /* Data of the root. */ + void *data; + }; + + int ggc_set_dynamic_root_mark (const void *); + void ggc_mark_dynamic_root (void (*) (void *), void *); + struct dynamic_root *register_dynamic_root (void (*) (void *), void *); + void unregister_dynamic_root (struct dynamic_root *); + /* Save and restore the string pool entries for PCH. */ extern void gt_pch_save_stringpool (void); Index: ggc-common.c =================================================================== *** ggc-common.c (revision 125526) --- ggc-common.c (working copy) *************** bool ggc_force_collect; *** 67,72 **** --- 67,76 ---- /* Statistics about the allocation. */ static ggc_statistics *ggc_stats; + /* Dynamic roots. */ + + static struct dynamic_root *dynamic_roots; + struct traversal_state; static int ggc_htab_delete (void **, void *); *************** ggc_htab_delete (void **slot, void *info *** 97,102 **** --- 101,166 ---- return 1; } + /* Mark function for objects that serve as dynamic ggc roots. Returns + 1 if it is called because of invocation of the gc traversal function + from ggc_mark_dynamic_root, and 0 otherwise. */ + + static bool called_from_ggc_mark_dynamic_root; + int + ggc_set_dynamic_root_mark (const void *p ATTRIBUTE_UNUSED) + { + if (called_from_ggc_mark_dynamic_root) + { + called_from_ggc_mark_dynamic_root = false; + return 1; + } + + return 0; + } + + /* Marks dynamic root ROOT, and traverse it using MARK_FUNCTION. */ + + void + ggc_mark_dynamic_root (void (*mark_function) (void *), void *root) + { + called_from_ggc_mark_dynamic_root = true; + mark_function (root); + called_from_ggc_mark_dynamic_root = false; + } + + /* Registers and returns a dynamic root with marking function MARK. DATA are + passed to MARK when it is run. */ + + struct dynamic_root * + register_dynamic_root (void (*mark) (void *), void *data) + { + struct dynamic_root *dr = XNEW (struct dynamic_root); + + dr->mark = mark; + dr->data = data; + dr->next = dynamic_roots; + dr->prev = NULL; + if (dr->next) + dr->next->prev = dr; + dynamic_roots = dr; + + return dr; + } + + /* Unregisters and releases a dynamic root DR. */ + + void + unregister_dynamic_root (struct dynamic_root *dr) + { + if (dr->next) + dr->next->prev = dr->prev; + + if (dr->prev) + dr->prev->next = dr->next; + else + dynamic_roots = dr->next; + } + /* Iterate through all registered roots and mark each element. */ void *************** ggc_mark_roots (void) *** 106,111 **** --- 170,176 ---- const struct ggc_root_tab *rti; const struct ggc_cache_tab *const *ct; const struct ggc_cache_tab *cti; + struct dynamic_root *dr; size_t i; for (rt = gt_ggc_deletable_rtab; *rt; rt++) *************** ggc_mark_roots (void) *** 117,122 **** --- 182,190 ---- for (i = 0; i < rti->nelt; i++) (*rti->cb)(*(void **)((char *)rti->base + rti->stride * i)); + for (dr = dynamic_roots; dr; dr = dr->next) + dr->mark (dr->data); + ggc_mark_stringpool (); /* Now scan all hash tables that have objects which are to be deleted if Index: tree-flow.h =================================================================== *** tree-flow.h (revision 125526) --- tree-flow.h (working copy) *************** extern void make_abnormal_goto_edges (ba *** 775,782 **** extern void replace_uses_by (tree, tree); extern void start_recording_case_labels (void); extern void end_recording_case_labels (void); ! extern basic_block move_sese_region_to_fn (struct function *, basic_block, ! basic_block); void remove_edge_and_dominated_blocks (edge); /* In tree-cfgcleanup.c */ --- 775,782 ---- extern void replace_uses_by (tree, tree); extern void start_recording_case_labels (void); extern void end_recording_case_labels (void); ! extern basic_block move_sese_region_to_fn (struct function *, basic_block *, ! basic_block *); void remove_edge_and_dominated_blocks (edge); /* In tree-cfgcleanup.c */ Index: Makefile.in =================================================================== *** Makefile.in (revision 125526) --- Makefile.in (working copy) *************** value-prof.o : value-prof.c $(CONFIG_H) *** 2520,2526 **** loop-doloop.o : loop-doloop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(RTL_H) $(FLAGS_H) $(EXPR_H) hard-reg-set.h $(BASIC_BLOCK_H) $(TM_P_H) \ toplev.h $(CFGLOOP_H) output.h $(PARAMS_H) $(TARGET_H) ! alloc-pool.o : alloc-pool.c $(CONFIG_H) $(SYSTEM_H) alloc-pool.h $(HASHTAB_H) flow.o : flow.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ $(TREE_H) $(FLAGS_H) insn-config.h $(BASIC_BLOCK_H) $(REGS_H) \ hard-reg-set.h output.h toplev.h $(RECOG_H) $(FUNCTION_H) except.h \ --- 2520,2527 ---- loop-doloop.o : loop-doloop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(RTL_H) $(FLAGS_H) $(EXPR_H) hard-reg-set.h $(BASIC_BLOCK_H) $(TM_P_H) \ toplev.h $(CFGLOOP_H) output.h $(PARAMS_H) $(TARGET_H) ! alloc-pool.o : alloc-pool.c $(CONFIG_H) $(SYSTEM_H) alloc-pool.h $(HASHTAB_H) \ ! pointer-set.h $(GGC_H) flow.o : flow.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ $(TREE_H) $(FLAGS_H) insn-config.h $(BASIC_BLOCK_H) $(REGS_H) \ hard-reg-set.h output.h toplev.h $(RECOG_H) $(FUNCTION_H) except.h \ Index: basic-block.h =================================================================== *** basic-block.h (revision 125526) --- basic-block.h (working copy) *************** struct rtl_bb_info; *** 211,217 **** basic blocks. */ /* Basic block information indexed by block number. */ ! struct basic_block_def GTY((chain_next ("%h.next_bb"), chain_prev ("%h.prev_bb"))) { /* The edges into and out of the block. */ VEC(edge,gc) *preds; --- 211,217 ---- basic blocks. */ /* Basic block information indexed by block number. */ ! struct basic_block_def GTY((custom_mark ("ggc_set_dynamic_root_mark"))) { /* The edges into and out of the block. */ VEC(edge,gc) *preds; *************** struct control_flow_graph GTY(()) *** 383,388 **** --- 383,394 ---- only used for the tree CFG. */ VEC(basic_block,gc) *x_label_to_block_map; + /* Pool for bb allocation. */ + struct alloc_pool_def * GTY ((skip)) bb_pool; + + /* GC roots in this alloc pool. */ + struct dynamic_root * GTY ((skip)) bb_pool_root; + enum profile_status { PROFILE_ABSENT, PROFILE_GUESSED, Index: tree-cfg.c =================================================================== *** tree-cfg.c (revision 125526) --- tree-cfg.c (working copy) *************** move_stmt_r (tree *tp, int *walk_subtree *** 4580,4623 **** If UPDATE_EDGE_COUNT_P is true, the edge counts on both CFGs is updated to reflect the moved edges. On exit, local variables that need to be removed from CFUN->UNEXPANDED_VAR_LIST will have been added to VARS_TO_REMOVE. */ ! static void move_block_to_fn (struct function *dest_cfun, basic_block bb, basic_block after, bool update_edge_count_p, bitmap vars_to_remove, htab_t new_label_map, int eh_offset) { struct control_flow_graph *cfg; - edge_iterator ei; - edge e; block_stmt_iterator si; struct move_stmt_d d; unsigned old_len, new_len; /* Remove BB from dominance structures. */ delete_from_dominance_info (CDI_DOMINATORS, bb); ! /* Link BB to the new linked list. */ ! move_block_after (bb, after); /* Update the edge count in the corresponding flowgraphs. */ if (update_edge_count_p) ! FOR_EACH_EDGE (e, ei, bb->succs) ! { ! cfun->cfg->x_n_edges--; ! dest_cfun->cfg->x_n_edges++; ! } ! /* Remove BB from the original basic block array. */ VEC_replace (basic_block, cfun->cfg->x_basic_block_info, bb->index, NULL); ! cfun->cfg->x_n_basic_blocks--; /* Grow DEST_CFUN's basic block array if needed. */ cfg = dest_cfun->cfg; cfg->x_n_basic_blocks++; ! if (bb->index >= cfg->x_last_basic_block) ! cfg->x_last_basic_block = bb->index + 1; old_len = VEC_length (basic_block, cfg->x_basic_block_info); if ((unsigned) cfg->x_last_basic_block >= old_len) --- 4580,4644 ---- If UPDATE_EDGE_COUNT_P is true, the edge counts on both CFGs is updated to reflect the moved edges. + The block has to be copied when it is moved, the newly created + block is returned. + On exit, local variables that need to be removed from CFUN->UNEXPANDED_VAR_LIST will have been added to VARS_TO_REMOVE. */ ! static basic_block move_block_to_fn (struct function *dest_cfun, basic_block bb, basic_block after, bool update_edge_count_p, bitmap vars_to_remove, htab_t new_label_map, int eh_offset) { struct control_flow_graph *cfg; block_stmt_iterator si; struct move_stmt_d d; unsigned old_len, new_len; + basic_block new_bb; + struct function *act_cfun = cfun; + edge e; + edge_iterator ei; + + /* Create an exact duplicate of the basic block, allocated in the destination + cfg. */ + cfun = dest_cfun; + new_bb = alloc_block (); + cfun = act_cfun; + *new_bb = *bb; /* Remove BB from dominance structures. */ delete_from_dominance_info (CDI_DOMINATORS, bb); ! /* Link new block to the destination function bb list. */ ! move_block_after (new_bb, after); /* Update the edge count in the corresponding flowgraphs. */ if (update_edge_count_p) ! { ! cfun->cfg->x_n_edges -= EDGE_COUNT (bb->succs); ! dest_cfun->cfg->x_n_edges += EDGE_COUNT (bb->succs); ! } ! /* Replace BB by NEW_BB in the edge lists. */ ! FOR_EACH_EDGE (e, ei, bb->succs) ! { ! e->src = new_bb; ! } ! FOR_EACH_EDGE (e, ei, bb->preds) ! { ! e->dest = new_bb; ! } ! ! /* Remove BB from the source function. */ VEC_replace (basic_block, cfun->cfg->x_basic_block_info, bb->index, NULL); ! expunge_block (bb); /* Grow DEST_CFUN's basic block array if needed. */ cfg = dest_cfun->cfg; cfg->x_n_basic_blocks++; ! if (new_bb->index >= cfg->x_last_basic_block) ! cfg->x_last_basic_block = new_bb->index + 1; old_len = VEC_length (basic_block, cfg->x_basic_block_info); if ((unsigned) cfg->x_last_basic_block >= old_len) *************** move_block_to_fn (struct function *dest_ *** 4628,4644 **** } VEC_replace (basic_block, cfg->x_basic_block_info, ! bb->index, bb); /* The statements in BB need to be associated with a new TREE_BLOCK. Labels need to be associated with a new label-to-block map. */ memset (&d, 0, sizeof (d)); d.vars_to_remove = vars_to_remove; ! for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si)) { tree stmt = bsi_stmt (si); int region; d.from_context = cfun->decl; d.to_context = dest_cfun->decl; --- 4649,4667 ---- } VEC_replace (basic_block, cfg->x_basic_block_info, ! new_bb->index, new_bb); /* The statements in BB need to be associated with a new TREE_BLOCK. Labels need to be associated with a new label-to-block map. */ memset (&d, 0, sizeof (d)); d.vars_to_remove = vars_to_remove; ! for (si = bsi_start (new_bb); !bsi_end_p (si); bsi_next (&si)) { tree stmt = bsi_stmt (si); int region; + + stmt_ann (stmt)->bb = new_bb; d.from_context = cfun->decl; d.to_context = dest_cfun->decl; *************** move_block_to_fn (struct function *dest_ *** 4664,4670 **** cfg->x_label_to_block_map, new_len); } ! VEC_replace (basic_block, cfg->x_label_to_block_map, uid, bb); VEC_replace (basic_block, cfun->cfg->x_label_to_block_map, uid, NULL); gcc_assert (DECL_CONTEXT (label) == dest_cfun->decl); --- 4687,4693 ---- cfg->x_label_to_block_map, new_len); } ! VEC_replace (basic_block, cfg->x_label_to_block_map, uid, new_bb); VEC_replace (basic_block, cfun->cfg->x_label_to_block_map, uid, NULL); gcc_assert (DECL_CONTEXT (label) == dest_cfun->decl); *************** move_block_to_fn (struct function *dest_ *** 4687,4692 **** --- 4710,4717 ---- gimple_remove_stmt_histograms (cfun, stmt); } } + + return new_bb; } /* Examine the statements in BB (which is in SRC_CFUN); find and return *************** new_label_mapper (tree decl, void *data) *** 4745,4767 **** return m->to; } ! /* Move a single-entry, single-exit region delimited by ENTRY_BB and ! EXIT_BB to function DEST_CFUN. The whole region is replaced by a single basic block in the original CFG and the new basic block is returned. DEST_CFUN must not have a CFG yet. Note that the region need not be a pure SESE region. Blocks inside the region may contain calls to abort/exit. The only restriction ! is that ENTRY_BB should be the only entry point and it must ! dominate EXIT_BB. All local variables referenced in the region are assumed to be in the corresponding BLOCK_VARS and unexpanded variable lists associated with DEST_CFUN. */ basic_block ! move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb, ! basic_block exit_bb) { VEC(basic_block,heap) *bbs; basic_block after, bb, *entry_pred, *exit_succ; --- 4770,4795 ---- return m->to; } ! /* Move a single-entry, single-exit region delimited by *ENTRY_BB_P and ! *EXIT_BB_P to function DEST_CFUN. The whole region is replaced by a single basic block in the original CFG and the new basic block is returned. DEST_CFUN must not have a CFG yet. Note that the region need not be a pure SESE region. Blocks inside the region may contain calls to abort/exit. The only restriction ! is that *ENTRY_BB_P should be the only entry point and it must ! dominate *EXIT_BB_P. ! ! *ENTRY_BB_P and EXIT_BB_P are duplicated during the move, and their ! new values are returned. All local variables referenced in the region are assumed to be in the corresponding BLOCK_VARS and unexpanded variable lists associated with DEST_CFUN. */ basic_block ! move_sese_region_to_fn (struct function *dest_cfun, basic_block *entry_bb_p, ! basic_block *exit_bb_p) { VEC(basic_block,heap) *bbs; basic_block after, bb, *entry_pred, *exit_succ; *************** move_sese_region_to_fn (struct function *** 4772,4777 **** --- 4800,4807 ---- edge_iterator ei; bitmap vars_to_remove; htab_t new_label_map; + basic_block entry_bb = *entry_bb_p; + basic_block exit_bb = *exit_bb_p; saved_cfun = cfun; *************** move_sese_region_to_fn (struct function *** 4861,4869 **** /* No need to update edge counts on the last block. It has already been updated earlier when we detached the region from the original CFG. */ ! move_block_to_fn (dest_cfun, bb, after, bb != exit_bb, vars_to_remove, ! new_label_map, eh_offset); ! after = bb; } if (new_label_map) --- 4891,4903 ---- /* No need to update edge counts on the last block. It has already been updated earlier when we detached the region from the original CFG. */ ! after = move_block_to_fn (dest_cfun, bb, after, ! bb != exit_bb, vars_to_remove, ! new_label_map, eh_offset); ! if (bb == entry_bb) ! entry_bb = after; ! if (bb == exit_bb) ! exit_bb = after; } if (new_label_map) *************** move_sese_region_to_fn (struct function *** 4926,4931 **** --- 4960,4968 ---- free_dominance_info (CDI_POST_DOMINATORS); VEC_free (basic_block, heap, bbs); + *entry_bb_p = entry_bb; + *exit_bb_p = exit_bb; + return bb; }