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.c147
1 files changed, 127 insertions, 20 deletions
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index b7f147c..6f0e947 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -4591,6 +4591,7 @@ struct move_stmt_d
tree from_context;
tree to_context;
bitmap vars_to_remove;
+ htab_t new_label_map;
bool remap_decls_p;
};
@@ -4599,39 +4600,62 @@ struct move_stmt_d
variable referenced in *TP. */
static tree
-move_stmt_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, void *data)
+move_stmt_r (tree *tp, int *walk_subtrees, void *data)
{
struct move_stmt_d *p = (struct move_stmt_d *) data;
+ tree t = *tp;
- if (p->block && IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (*tp))))
- TREE_BLOCK (*tp) = p->block;
+ if (p->block && IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (t))))
+ TREE_BLOCK (t) = p->block;
- if (OMP_DIRECTIVE_P (*tp))
+ if (OMP_DIRECTIVE_P (t) && TREE_CODE (t) != OMP_RETURN_EXPR)
{
/* Do not remap variables inside OMP directives. Variables
referenced in clauses and directive header belong to the
parent function and should not be moved into the child
function. */
+ bool save_remap_decls_p = p->remap_decls_p;
p->remap_decls_p = false;
- }
+ *walk_subtrees = 0;
+
+ walk_tree (&OMP_BODY (t), move_stmt_r, p, NULL);
- if (p->remap_decls_p
- && DECL_P (*tp)
- && DECL_CONTEXT (*tp) == p->from_context)
+ p->remap_decls_p = save_remap_decls_p;
+ }
+ else if (DECL_P (t) && DECL_CONTEXT (t) == p->from_context)
{
- DECL_CONTEXT (*tp) = p->to_context;
+ if (TREE_CODE (t) == LABEL_DECL)
+ {
+ if (p->new_label_map)
+ {
+ struct tree_map in, *out;
+ in.from = t;
+ out = htab_find_with_hash (p->new_label_map, &in, DECL_UID (t));
+ if (out)
+ *tp = t = out->to;
+ }
- if (TREE_CODE (*tp) == VAR_DECL)
+ DECL_CONTEXT (t) = p->to_context;
+ }
+ else if (p->remap_decls_p)
{
- struct function *f = DECL_STRUCT_FUNCTION (p->to_context);
- f->unexpanded_var_list = tree_cons (0, *tp, f->unexpanded_var_list);
+ DECL_CONTEXT (t) = p->to_context;
- /* Mark *TP 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 (*tp));
+ if (TREE_CODE (t) == VAR_DECL)
+ {
+ 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));
+ }
}
}
+ else if (TYPE_P (t))
+ *walk_subtrees = 0;
return NULL_TREE;
}
@@ -4650,7 +4674,7 @@ move_stmt_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, void *data)
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)
+ bitmap vars_to_remove, htab_t new_label_map, int eh_offset)
{
struct control_flow_graph *cfg;
edge_iterator ei;
@@ -4701,10 +4725,12 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb,
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);
@@ -4736,11 +4762,66 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb,
if (uid >= dest_cfun->last_label_uid)
dest_cfun->last_label_uid = uid + 1;
}
+ else if (TREE_CODE (stmt) == RESX_EXPR && eh_offset != 0)
+ TREE_OPERAND (stmt, 0) =
+ build_int_cst (NULL_TREE,
+ TREE_INT_CST_LOW (TREE_OPERAND (stmt, 0))
+ + eh_offset);
+
+ region = lookup_stmt_eh_region (stmt);
+ if (region >= 0)
+ {
+ add_stmt_to_eh_region_fn (dest_cfun, stmt, region + eh_offset);
+ remove_stmt_from_eh_region (stmt);
+ }
+ }
+}
+
+/* Examine the statements in BB (which is in SRC_CFUN); find and return
+ the outermost EH region. Use REGION as the incoming base EH region. */
+
+static int
+find_outermost_region_in_block (struct function *src_cfun,
+ basic_block bb, int region)
+{
+ block_stmt_iterator si;
+
+ for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
+ {
+ tree stmt = bsi_stmt (si);
+ int stmt_region;
- remove_stmt_from_eh_region (stmt);
+ stmt_region = lookup_stmt_eh_region_fn (src_cfun, stmt);
+ if (stmt_region > 0
+ && (region < 0 || eh_region_outer_p (src_cfun, stmt_region, region)))
+ region = stmt_region;
}
+
+ return region;
}
+static tree
+new_label_mapper (tree decl, void *data)
+{
+ htab_t hash = (htab_t) data;
+ struct tree_map *m;
+ void **slot;
+
+ gcc_assert (TREE_CODE (decl) == LABEL_DECL);
+
+ m = xmalloc (sizeof (struct tree_map));
+ m->hash = DECL_UID (decl);
+ m->from = decl;
+ m->to = create_artificial_label ();
+ LABEL_DECL_UID (m->to) = LABEL_DECL_UID (decl);
+
+ slot = htab_find_slot_with_hash (hash, m, m->hash, INSERT);
+ gcc_assert (*slot == NULL);
+
+ *slot = m;
+
+ 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
@@ -4763,11 +4844,12 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
VEC(basic_block,heap) *bbs;
basic_block after, bb, *entry_pred, *exit_succ;
struct function *saved_cfun;
- int *entry_flag, *exit_flag;
+ int *entry_flag, *exit_flag, eh_offset;
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;
@@ -4813,7 +4895,28 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
/* Switch context to the child function to initialize DEST_FN's CFG. */
gcc_assert (dest_cfun->cfg == NULL);
cfun = dest_cfun;
+
init_empty_tree_cfg ();
+
+ /* Initialize EH information for the new function. */
+ eh_offset = 0;
+ new_label_map = NULL;
+ if (saved_cfun->eh)
+ {
+ int region = -1;
+
+ for (i = 0; VEC_iterate (basic_block, bbs, i, bb); i++)
+ region = find_outermost_region_in_block (saved_cfun, bb, region);
+
+ init_eh_for_function ();
+ if (region != -1)
+ {
+ new_label_map = htab_create (17, tree_map_hash, tree_map_eq, free);
+ eh_offset = duplicate_eh_regions (saved_cfun, new_label_mapper,
+ new_label_map, region, 0);
+ }
+ }
+
cfun = saved_cfun;
/* Move blocks from BBS into DEST_CFUN. */
@@ -4825,10 +4928,14 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
/* 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_to_remove,
+ 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. */