aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-cfg.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree-cfg.c')
-rw-r--r--gcc/tree-cfg.c258
1 files changed, 195 insertions, 63 deletions
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 461f3f2..8400053 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. */
@@ -5248,13 +5249,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 +5366,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 +5385,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 +5412,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 +5440,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,6 +5455,7 @@ 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;
/* Remove BB from dominance structures. */
delete_from_dominance_info (CDI_DOMINATORS, bb);
@@ -5385,20 +5492,39 @@ 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 = PHI_CHAIN (phi))
+ {
+ use_operand_p use;
+ tree op = PHI_RESULT (phi);
+ ssa_op_iter oi;
+
+ if (!is_gimple_reg (op))
+ 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 +5567,8 @@ 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);
}
+
+ update_stmt (stmt);
}
}
@@ -5518,21 +5646,17 @@ 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;
/* If ENTRY does not strictly dominate EXIT, this cannot be an SESE
region. */
@@ -5540,10 +5664,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 +5683,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 +5699,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 +5714,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 +5742,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 +5776,41 @@ 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]);
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;