X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gcc%2Ftree-cfg.c;h=fd981f35b0e613b41142081ba7e9fa25a4527c57;hb=0e01499666a5032861459cd9fd07bdb8df149637;hp=461f3f2db25e30578bf8d73b8ec6b80ab7c21ce0;hpb=5ffeb913b1a455fe79c1c116fc75f09c21194815;p=gcc.git diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 461f3f2db25..fd981f35b0e 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-ssa-propagate.h" #include "value-prof.h" #include "pointer-set.h" +#include "tree-inline.h" /* This file contains functions for building the Control Flow Graph (CFG) for a function tree. */ @@ -104,7 +105,7 @@ static inline void change_bb_for_stmt (tree t, basic_block bb); /* Flowgraph optimization and cleanup. */ static void tree_merge_blocks (basic_block, basic_block); -static bool tree_can_merge_blocks_p (const_basic_block, const_basic_block); +static bool tree_can_merge_blocks_p (basic_block, basic_block); static void remove_bb (basic_block); static edge find_taken_edge_computed_goto (basic_block, tree); static edge find_taken_edge_cond_expr (basic_block, tree); @@ -1135,10 +1136,10 @@ group_case_labels (void) /* Checks whether we can merge block B into block A. */ static bool -tree_can_merge_blocks_p (const_basic_block a, const_basic_block b) +tree_can_merge_blocks_p (basic_block a, basic_block b) { const_tree stmt; - const_block_stmt_iterator bsi; + block_stmt_iterator bsi; tree phi; if (!single_succ_p (a)) @@ -1160,7 +1161,7 @@ tree_can_merge_blocks_p (const_basic_block a, const_basic_block b) cannot merge the blocks. */ /* This CONST_CAST is okay because last_stmt doesn't modify its argument and the return value is assign to a const_tree. */ - stmt = last_stmt (CONST_CAST_BB(a)); + stmt = last_stmt (CONST_CAST_BB (a)); if (stmt && stmt_ends_bb_p (stmt)) return false; @@ -1186,9 +1187,9 @@ tree_can_merge_blocks_p (const_basic_block a, const_basic_block b) } /* Do not remove user labels. */ - for (bsi = cbsi_start (b); !cbsi_end_p (bsi); cbsi_next (&bsi)) + for (bsi = bsi_start (b); !bsi_end_p (bsi); bsi_next (&bsi)) { - stmt = cbsi_stmt (bsi); + stmt = bsi_stmt (bsi); if (TREE_CODE (stmt) != LABEL_EXPR) break; if (!DECL_ARTIFICIAL (LABEL_EXPR_LABEL (stmt))) @@ -2458,7 +2459,7 @@ is_ctrl_altering_stmt (const_tree t) const_tree call; gcc_assert (t); - call = const_get_call_expr_in (t); + call = get_call_expr_in (CONST_CAST_TREE (t)); if (call) { /* A non-pure/const CALL_EXPR alters flow control if the current @@ -3769,22 +3770,23 @@ verify_gimple_expr (tree expr) case ADDR_EXPR: { tree op = TREE_OPERAND (expr, 0); - tree ptr_type; if (!is_gimple_addressable (op)) { error ("invalid operand in unary expression"); return true; } - ptr_type = build_pointer_type (TREE_TYPE (op)); - if (!useless_type_conversion_p (type, ptr_type) + if (TYPE_POINTER_TO (TREE_TYPE (op)) + && !useless_type_conversion_p (type, + TYPE_POINTER_TO (TREE_TYPE (op))) /* FIXME: a longstanding wart, &a == &a[0]. */ && (TREE_CODE (TREE_TYPE (op)) != ARRAY_TYPE - || !useless_type_conversion_p (type, - build_pointer_type (TREE_TYPE (TREE_TYPE (op)))))) + || (TYPE_POINTER_TO (TREE_TYPE (TREE_TYPE (op))) + && !useless_type_conversion_p (type, + TYPE_POINTER_TO (TREE_TYPE (TREE_TYPE (op))))))) { error ("type mismatch in address expression"); debug_generic_stmt (TREE_TYPE (expr)); - debug_generic_stmt (ptr_type); + debug_generic_stmt (TYPE_POINTER_TO (TREE_TYPE (op))); return true; } @@ -5007,6 +5009,52 @@ tree_duplicate_bb (basic_block bb) return new_bb; } +/* Adds phi node arguments for edge E_COPY after basic block duplication. */ + +static void +add_phi_args_after_copy_edge (edge e_copy) +{ + basic_block bb, bb_copy = e_copy->src, dest; + edge e; + edge_iterator ei; + tree phi, phi_copy, phi_next, def; + + if (!phi_nodes (e_copy->dest)) + return; + + bb = bb_copy->flags & BB_DUPLICATED ? get_bb_original (bb_copy) : bb_copy; + + if (e_copy->dest->flags & BB_DUPLICATED) + dest = get_bb_original (e_copy->dest); + else + dest = e_copy->dest; + + e = find_edge (bb, dest); + if (!e) + { + /* During loop unrolling the target of the latch edge is copied. + In this case we are not looking for edge to dest, but to + duplicated block whose original was dest. */ + FOR_EACH_EDGE (e, ei, bb->succs) + { + if ((e->dest->flags & BB_DUPLICATED) + && get_bb_original (e->dest) == dest) + break; + } + + gcc_assert (e != NULL); + } + + for (phi = phi_nodes (e->dest), phi_copy = phi_nodes (e_copy->dest); + phi; + phi = phi_next, phi_copy = PHI_CHAIN (phi_copy)) + { + phi_next = PHI_CHAIN (phi); + def = PHI_ARG_DEF_FROM_EDGE (phi, e); + add_phi_arg (phi_copy, def, e_copy); + } +} + /* Basic block BB_COPY was created by code duplication. Add phi node arguments for edges going out of BB_COPY. The blocks that were @@ -5015,54 +5063,23 @@ tree_duplicate_bb (basic_block bb) void add_phi_args_after_copy_bb (basic_block bb_copy) { - basic_block bb, dest; - edge e, e_copy; edge_iterator ei; - tree phi, phi_copy, phi_next, def; - - bb = get_bb_original (bb_copy); + edge e_copy; FOR_EACH_EDGE (e_copy, ei, bb_copy->succs) { - if (!phi_nodes (e_copy->dest)) - continue; - - if (e_copy->dest->flags & BB_DUPLICATED) - dest = get_bb_original (e_copy->dest); - else - dest = e_copy->dest; - - e = find_edge (bb, dest); - if (!e) - { - /* During loop unrolling the target of the latch edge is copied. - In this case we are not looking for edge to dest, but to - duplicated block whose original was dest. */ - FOR_EACH_EDGE (e, ei, bb->succs) - if ((e->dest->flags & BB_DUPLICATED) - && get_bb_original (e->dest) == dest) - break; - - gcc_assert (e != NULL); - } - - for (phi = phi_nodes (e->dest), phi_copy = phi_nodes (e_copy->dest); - phi; - phi = phi_next, phi_copy = PHI_CHAIN (phi_copy)) - { - phi_next = PHI_CHAIN (phi); - def = PHI_ARG_DEF_FROM_EDGE (phi, e); - add_phi_arg (phi_copy, def, e_copy); - } + add_phi_args_after_copy_edge (e_copy); } } /* Blocks in REGION_COPY array of length N_REGION were created by duplication of basic blocks. Add phi node arguments for edges - going from these blocks. */ + going from these blocks. If E_COPY is not NULL, also add + phi node arguments for its destination.*/ void -add_phi_args_after_copy (basic_block *region_copy, unsigned n_region) +add_phi_args_after_copy (basic_block *region_copy, unsigned n_region, + edge e_copy) { unsigned i; @@ -5071,6 +5088,8 @@ add_phi_args_after_copy (basic_block *region_copy, unsigned n_region) for (i = 0; i < n_region; i++) add_phi_args_after_copy_bb (region_copy[i]); + if (e_copy) + add_phi_args_after_copy_edge (e_copy); for (i = 0; i < n_region; i++) region_copy[i]->flags &= ~BB_DUPLICATED; @@ -5208,10 +5227,180 @@ tree_duplicate_sese_region (edge entry, edge exit, set_immediate_dominator (CDI_DOMINATORS, entry->dest, entry->src); VEC_safe_push (basic_block, heap, doms, get_bb_original (entry->dest)); iterate_fix_dominators (CDI_DOMINATORS, doms, false); - free (doms); + VEC_free (basic_block, heap, doms); /* Add the other PHI node arguments. */ - add_phi_args_after_copy (region_copy, n_region); + add_phi_args_after_copy (region_copy, n_region, NULL); + + /* Update the SSA web. */ + update_ssa (TODO_update_ssa); + + if (free_region_copy) + free (region_copy); + + free_original_copy_tables (); + return true; +} + +/* Duplicates REGION consisting of N_REGION blocks. The new blocks + are stored to REGION_COPY in the same order in that they appear + in REGION, if REGION_COPY is not NULL. ENTRY is the entry to + the region, EXIT an exit from it. The condition guarding EXIT + is moved to ENTRY. Returns true if duplication succeeds, false + otherwise. + + For example, + + some_code; + if (cond) + A; + else + B; + + is transformed to + + if (cond) + { + some_code; + A; + } + else + { + some_code; + B; + } +*/ + +bool +tree_duplicate_sese_tail (edge entry, edge exit, + basic_block *region, unsigned n_region, + basic_block *region_copy) +{ + unsigned i; + bool free_region_copy = false; + struct loop *loop = exit->dest->loop_father; + struct loop *orig_loop = entry->dest->loop_father; + basic_block switch_bb, entry_bb, nentry_bb; + VEC (basic_block, heap) *doms; + int total_freq = 0, exit_freq = 0; + gcov_type total_count = 0, exit_count = 0; + edge exits[2], nexits[2], e; + block_stmt_iterator bsi; + tree cond; + edge sorig, snew; + + gcc_assert (EDGE_COUNT (exit->src->succs) == 2); + exits[0] = exit; + exits[1] = EDGE_SUCC (exit->src, EDGE_SUCC (exit->src, 0) == exit); + + if (!can_copy_bbs_p (region, n_region)) + return false; + + /* Some sanity checking. Note that we do not check for all possible + missuses of the functions. I.e. if you ask to copy something weird + (e.g., in the example, if there is a jump from inside to the middle + of some_code, or come_code defines some of the values used in cond) + it will work, but the resulting code will not be correct. */ + for (i = 0; i < n_region; i++) + { + /* We do not handle subloops, i.e. all the blocks must belong to the + same loop. */ + if (region[i]->loop_father != orig_loop) + return false; + + if (region[i] == orig_loop->latch) + return false; + } + + initialize_original_copy_tables (); + set_loop_copy (orig_loop, loop); + + if (!region_copy) + { + region_copy = XNEWVEC (basic_block, n_region); + free_region_copy = true; + } + + gcc_assert (!need_ssa_update_p ()); + + /* Record blocks outside the region that are dominated by something + inside. */ + doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region); + + if (exit->src->count) + { + total_count = exit->src->count; + exit_count = exit->count; + /* Fix up corner cases, to avoid division by zero or creation of negative + frequencies. */ + if (exit_count > total_count) + exit_count = total_count; + } + else + { + total_freq = exit->src->frequency; + exit_freq = EDGE_FREQUENCY (exit); + /* Fix up corner cases, to avoid division by zero or creation of negative + frequencies. */ + if (total_freq == 0) + total_freq = 1; + if (exit_freq > total_freq) + exit_freq = total_freq; + } + + copy_bbs (region, n_region, region_copy, exits, 2, nexits, orig_loop, + split_edge_bb_loc (exit)); + if (total_count) + { + scale_bbs_frequencies_gcov_type (region, n_region, + total_count - exit_count, + total_count); + scale_bbs_frequencies_gcov_type (region_copy, n_region, exit_count, + total_count); + } + else + { + scale_bbs_frequencies_int (region, n_region, total_freq - exit_freq, + total_freq); + scale_bbs_frequencies_int (region_copy, n_region, exit_freq, total_freq); + } + + /* Create the switch block, and put the exit condition to it. */ + entry_bb = entry->dest; + nentry_bb = get_bb_copy (entry_bb); + if (!last_stmt (entry->src) + || !stmt_ends_bb_p (last_stmt (entry->src))) + switch_bb = entry->src; + else + switch_bb = split_edge (entry); + set_immediate_dominator (CDI_DOMINATORS, nentry_bb, switch_bb); + + bsi = bsi_last (switch_bb); + cond = last_stmt (exit->src); + gcc_assert (TREE_CODE (cond) == COND_EXPR); + bsi_insert_after (&bsi, unshare_expr (cond), BSI_NEW_STMT); + + sorig = single_succ_edge (switch_bb); + sorig->flags = exits[1]->flags; + snew = make_edge (switch_bb, nentry_bb, exits[0]->flags); + + /* Register the new edge from SWITCH_BB in loop exit lists. */ + rescan_loop_exit (snew, true, false); + + /* Add the PHI node arguments. */ + add_phi_args_after_copy (region_copy, n_region, snew); + + /* Get rid of now superfluous conditions and associated edges (and phi node + arguments). */ + e = redirect_edge_and_branch (exits[0], exits[1]->dest); + PENDING_STMT (e) = NULL_TREE; + e = redirect_edge_and_branch (nexits[1], nexits[0]->dest); + PENDING_STMT (e) = NULL_TREE; + + /* Anything that is outside of the region, but was dominated by something + inside needs to update dominance info. */ + iterate_fix_dominators (CDI_DOMINATORS, doms, false); + VEC_free (basic_block, heap, doms); /* Update the SSA web. */ update_ssa (TODO_update_ssa); @@ -5248,13 +5437,89 @@ gather_blocks_in_sese_region (basic_block entry, basic_block exit, } } +/* Replaces *TP with a duplicate (belonging to function TO_CONTEXT). + The duplicates are recorded in VARS_MAP. */ + +static void +replace_by_duplicate_decl (tree *tp, struct pointer_map_t *vars_map, + tree to_context) +{ + tree t = *tp, new_t; + struct function *f = DECL_STRUCT_FUNCTION (to_context); + void **loc; + + if (DECL_CONTEXT (t) == to_context) + return; + + loc = pointer_map_contains (vars_map, t); + + if (!loc) + { + loc = pointer_map_insert (vars_map, t); + + if (SSA_VAR_P (t)) + { + new_t = copy_var_decl (t, DECL_NAME (t), TREE_TYPE (t)); + f->unexpanded_var_list + = tree_cons (NULL_TREE, new_t, f->unexpanded_var_list); + } + else + { + gcc_assert (TREE_CODE (t) == CONST_DECL); + new_t = copy_node (t); + } + DECL_CONTEXT (new_t) = to_context; + + *loc = new_t; + } + else + new_t = *loc; + + *tp = new_t; +} + +/* Creates an ssa name in TO_CONTEXT equivalent to NAME. + VARS_MAP maps old ssa names and var_decls to the new ones. */ + +static tree +replace_ssa_name (tree name, struct pointer_map_t *vars_map, + tree to_context) +{ + void **loc; + tree new_name, decl = SSA_NAME_VAR (name); + + gcc_assert (is_gimple_reg (name)); + + loc = pointer_map_contains (vars_map, name); + + if (!loc) + { + replace_by_duplicate_decl (&decl, vars_map, to_context); + + push_cfun (DECL_STRUCT_FUNCTION (to_context)); + if (gimple_in_ssa_p (cfun)) + add_referenced_var (decl); + + new_name = make_ssa_name (decl, SSA_NAME_DEF_STMT (name)); + if (SSA_NAME_IS_DEFAULT_DEF (name)) + set_default_def (decl, new_name); + pop_cfun (); + + loc = pointer_map_insert (vars_map, name); + *loc = new_name; + } + else + new_name = *loc; + + return new_name; +} struct move_stmt_d { tree block; tree from_context; tree to_context; - bitmap vars_to_remove; + struct pointer_map_t *vars_map; htab_t new_label_map; bool remap_decls_p; }; @@ -5289,9 +5554,11 @@ move_stmt_r (tree *tp, int *walk_subtrees, void *data) p->remap_decls_p = save_remap_decls_p; } - else if (DECL_P (t) && DECL_CONTEXT (t) == p->from_context) + else if (DECL_P (t) || TREE_CODE (t) == SSA_NAME) { - if (TREE_CODE (t) == LABEL_DECL) + if (TREE_CODE (t) == SSA_NAME) + *tp = replace_ssa_name (t, p->vars_map, p->to_context); + else if (TREE_CODE (t) == LABEL_DECL) { if (p->new_label_map) { @@ -5306,20 +5573,26 @@ move_stmt_r (tree *tp, int *walk_subtrees, void *data) } else if (p->remap_decls_p) { - DECL_CONTEXT (t) = p->to_context; - - if (TREE_CODE (t) == VAR_DECL) + /* Replace T with its duplicate. T should no longer appear in the + parent function, so this looks wasteful; however, it may appear + in referenced_vars, and more importantly, as virtual operands of + statements, and in alias lists of other variables. It would be + quite difficult to expunge it from all those places. ??? It might + suffice to do this for addressable variables. */ + if ((TREE_CODE (t) == VAR_DECL + && !is_global_var (t)) + || TREE_CODE (t) == CONST_DECL) + replace_by_duplicate_decl (tp, p->vars_map, p->to_context); + + if (SSA_VAR_P (t) + && gimple_in_ssa_p (cfun)) { - struct function *f = DECL_STRUCT_FUNCTION (p->to_context); - f->unexpanded_var_list - = tree_cons (0, t, f->unexpanded_var_list); - - /* Mark T to be removed from the original function, - otherwise it will be given a DECL_RTL when the - original function is expanded. */ - bitmap_set_bit (p->vars_to_remove, DECL_UID (t)); + push_cfun (DECL_STRUCT_FUNCTION (p->to_context)); + add_referenced_var (*tp); + pop_cfun (); } } + *walk_subtrees = 0; } else if (TYPE_P (t)) *walk_subtrees = 0; @@ -5327,6 +5600,26 @@ move_stmt_r (tree *tp, int *walk_subtrees, void *data) return NULL_TREE; } +/* Marks virtual operands of all statements in basic blocks BBS for + renaming. */ + +static void +mark_virtual_ops_in_region (VEC (basic_block,heap) *bbs) +{ + tree phi; + block_stmt_iterator bsi; + basic_block bb; + unsigned i; + + for (i = 0; VEC_iterate (basic_block, bbs, i, bb); i++) + { + for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi)) + mark_virtual_ops_for_renaming (phi); + + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + mark_virtual_ops_for_renaming (bsi_stmt (bsi)); + } +} /* Move basic block BB from function CFUN to function DEST_FN. The block is moved out of the original linked list and placed after @@ -5335,13 +5628,14 @@ move_stmt_r (tree *tp, int *walk_subtrees, void *data) 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. */ + The local variables are remapped to new instances, VARS_MAP is used + to record the mapping. */ 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 pointer_map_t *vars_map, htab_t new_label_map, + int eh_offset) { struct control_flow_graph *cfg; edge_iterator ei; @@ -5349,9 +5643,12 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb, block_stmt_iterator si; struct move_stmt_d d; unsigned old_len, new_len; + tree phi, next_phi; /* Remove BB from dominance structures. */ delete_from_dominance_info (CDI_DOMINATORS, bb); + if (current_loops) + remove_bb_from_loops (bb); /* Link BB to the new linked list. */ move_block_after (bb, after); @@ -5385,20 +5682,45 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb, VEC_replace (basic_block, cfg->x_basic_block_info, bb->index, bb); + /* Remap the variables in phi nodes. */ + for (phi = phi_nodes (bb); phi; phi = next_phi) + { + use_operand_p use; + tree op = PHI_RESULT (phi); + ssa_op_iter oi; + + next_phi = PHI_CHAIN (phi); + if (!is_gimple_reg (op)) + { + /* Remove the phi nodes for virtual operands (alias analysis will be + run for the new function, anyway). */ + remove_phi_node (phi, NULL, true); + continue; + } + + SET_PHI_RESULT (phi, replace_ssa_name (op, vars_map, dest_cfun->decl)); + FOR_EACH_PHI_ARG (use, phi, oi, SSA_OP_USE) + { + op = USE_FROM_PTR (use); + if (TREE_CODE (op) == SSA_NAME) + SET_USE (use, replace_ssa_name (op, vars_map, dest_cfun->decl)); + } + } + /* 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; + d.vars_map = vars_map; + d.from_context = cfun->decl; + d.to_context = dest_cfun->decl; + d.new_label_map = new_label_map; 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; d.remap_decls_p = true; - d.new_label_map = new_label_map; if (TREE_BLOCK (stmt)) d.block = DECL_INITIAL (dest_cfun->decl); @@ -5441,6 +5763,13 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb, gimple_duplicate_stmt_histograms (dest_cfun, stmt, cfun, stmt); gimple_remove_stmt_histograms (cfun, stmt); } + + /* We cannot leave any operands allocated from the operand caches of + the current function. */ + free_stmt_operands (stmt); + push_cfun (dest_cfun); + update_stmt (stmt); + pop_cfun (); } } @@ -5518,21 +5847,18 @@ 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; - struct function *saved_cfun; + VEC(basic_block,heap) *bbs, *dom_bbs; + basic_block dom_entry = get_immediate_dominator (CDI_DOMINATORS, entry_bb); + basic_block after, bb, *entry_pred, *exit_succ, abb; + struct function *saved_cfun = cfun; int *entry_flag, *exit_flag, eh_offset; + unsigned *entry_prob, *exit_prob; unsigned i, num_entry_edges, num_exit_edges; edge e; edge_iterator ei; - bitmap vars_to_remove; htab_t new_label_map; - - saved_cfun = cfun; - - /* Collect all the blocks in the region. Manually add ENTRY_BB - because it won't be added by dfs_enumerate_from. */ - calculate_dominance_info (CDI_DOMINATORS); + struct pointer_map_t *vars_map; + struct loop *loop = entry_bb->loop_father; /* If ENTRY does not strictly dominate EXIT, this cannot be an SESE region. */ @@ -5540,10 +5866,18 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb, && (!exit_bb || dominated_by_p (CDI_DOMINATORS, exit_bb, entry_bb))); + /* Collect all the blocks in the region. Manually add ENTRY_BB + because it won't be added by dfs_enumerate_from. */ bbs = NULL; VEC_safe_push (basic_block, heap, bbs, entry_bb); gather_blocks_in_sese_region (entry_bb, exit_bb, &bbs); + /* The blocks that used to be dominated by something in BBS will now be + dominated by the new block. */ + dom_bbs = get_dominated_by_region (CDI_DOMINATORS, + VEC_address (basic_block, bbs), + VEC_length (basic_block, bbs)); + /* Detach ENTRY_BB and EXIT_BB from CFUN->CFG. We need to remember the predecessor edges to ENTRY_BB and the successor edges to EXIT_BB so that we can re-attach them to the new basic block that @@ -5551,9 +5885,11 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb, num_entry_edges = EDGE_COUNT (entry_bb->preds); entry_pred = (basic_block *) xcalloc (num_entry_edges, sizeof (basic_block)); entry_flag = (int *) xcalloc (num_entry_edges, sizeof (int)); + entry_prob = XNEWVEC (unsigned, num_entry_edges); i = 0; for (ei = ei_start (entry_bb->preds); (e = ei_safe_edge (ei)) != NULL;) { + entry_prob[i] = e->probability; entry_flag[i] = e->flags; entry_pred[i++] = e->src; remove_edge (e); @@ -5565,9 +5901,11 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb, exit_succ = (basic_block *) xcalloc (num_exit_edges, sizeof (basic_block)); exit_flag = (int *) xcalloc (num_exit_edges, sizeof (int)); + exit_prob = XNEWVEC (unsigned, num_exit_edges); i = 0; for (ei = ei_start (exit_bb->succs); (e = ei_safe_edge (ei)) != NULL;) { + exit_prob[i] = e->probability; exit_flag[i] = e->flags; exit_succ[i++] = e->dest; remove_edge (e); @@ -5578,11 +5916,12 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb, num_exit_edges = 0; exit_succ = NULL; exit_flag = NULL; + exit_prob = NULL; } /* Switch context to the child function to initialize DEST_FN's CFG. */ gcc_assert (dest_cfun->cfg == NULL); - set_cfun (dest_cfun); + push_cfun (dest_cfun); init_empty_tree_cfg (); @@ -5605,46 +5944,30 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb, } } - set_cfun (saved_cfun); + pop_cfun (); + + /* The ssa form for virtual operands in the source function will have to + be repaired. We do not care for the real operands -- the sese region + must be closed with respect to those. */ + mark_virtual_ops_in_region (bbs); /* Move blocks from BBS into DEST_CFUN. */ gcc_assert (VEC_length (basic_block, bbs) >= 2); after = dest_cfun->cfg->x_entry_block_ptr; - vars_to_remove = BITMAP_ALLOC (NULL); + vars_map = pointer_map_create (); for (i = 0; VEC_iterate (basic_block, bbs, i, bb); i++) { /* 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, + move_block_to_fn (dest_cfun, bb, after, bb != exit_bb, vars_map, new_label_map, eh_offset); after = bb; } if (new_label_map) htab_delete (new_label_map); - - /* Remove the variables marked in VARS_TO_REMOVE from - CFUN->UNEXPANDED_VAR_LIST. Otherwise, they will be given a - DECL_RTL in the context of CFUN. */ - if (!bitmap_empty_p (vars_to_remove)) - { - tree *p; - - for (p = &cfun->unexpanded_var_list; *p; ) - { - tree var = TREE_VALUE (*p); - if (bitmap_bit_p (vars_to_remove, DECL_UID (var))) - { - *p = TREE_CHAIN (*p); - continue; - } - - p = &TREE_CHAIN (*p); - } - } - - BITMAP_FREE (vars_to_remove); + pointer_map_destroy (vars_map); /* Rewire the entry and exit blocks. The successor to the entry block turns into the successor of DEST_FN's ENTRY_BLOCK_PTR in @@ -5655,30 +5978,43 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb, FIXME, this is silly. The CFG ought to become a parameter to these helpers. */ - set_cfun (dest_cfun); + push_cfun (dest_cfun); make_edge (ENTRY_BLOCK_PTR, entry_bb, EDGE_FALLTHRU); if (exit_bb) make_edge (exit_bb, EXIT_BLOCK_PTR, 0); - set_cfun (saved_cfun); + pop_cfun (); /* Back in the original function, the SESE region has disappeared, create a new basic block in its place. */ bb = create_empty_bb (entry_pred[0]); + if (current_loops) + add_bb_to_loop (bb, loop); for (i = 0; i < num_entry_edges; i++) - make_edge (entry_pred[i], bb, entry_flag[i]); + { + e = make_edge (entry_pred[i], bb, entry_flag[i]); + e->probability = entry_prob[i]; + } for (i = 0; i < num_exit_edges; i++) - make_edge (bb, exit_succ[i], exit_flag[i]); + { + e = make_edge (bb, exit_succ[i], exit_flag[i]); + e->probability = exit_prob[i]; + } + + set_immediate_dominator (CDI_DOMINATORS, bb, dom_entry); + for (i = 0; VEC_iterate (basic_block, dom_bbs, i, abb); i++) + set_immediate_dominator (CDI_DOMINATORS, abb, bb); + VEC_free (basic_block, heap, dom_bbs); if (exit_bb) { + free (exit_prob); free (exit_flag); free (exit_succ); } + free (entry_prob); free (entry_flag); free (entry_pred); - free_dominance_info (CDI_DOMINATORS); - free_dominance_info (CDI_POST_DOMINATORS); VEC_free (basic_block, heap, bbs); return bb; @@ -5905,10 +6241,10 @@ debug_loop_ir (void) otherwise. */ static bool -tree_block_ends_with_call_p (const_basic_block bb) +tree_block_ends_with_call_p (basic_block bb) { - const_block_stmt_iterator bsi = cbsi_last (bb); - return const_get_call_expr_in (cbsi_stmt (bsi)) != NULL; + block_stmt_iterator bsi = bsi_last (bb); + return get_call_expr_in (bsi_stmt (bsi)) != NULL; }