aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Henderson <rth@redhat.com>2006-03-22 04:50:45 -0800
committerRichard Henderson <rth@gcc.gnu.org>2006-03-22 04:50:45 -0800
commitfad41cd7d43ffce40a20f11cfbe68da548ef6b79 (patch)
tree600f6369cacf022589c2e874590e5a90eb2f99e5
parentee51e035d90930ba62d16122a40ffd3188f44c2c (diff)
downloadgcc-fad41cd7d43ffce40a20f11cfbe68da548ef6b79.zip
gcc-fad41cd7d43ffce40a20f11cfbe68da548ef6b79.tar.gz
gcc-fad41cd7d43ffce40a20f11cfbe68da548ef6b79.tar.bz2
re PR middle-end/26084 (ICE (segfault) on C++ OpenMP code)
PR middle-end/26084 * except.c (duplicate_eh_regions_0): New. (duplicate_eh_region_1): Duplicate the children of the node as well as the node itself. Link them up properly. (duplicate_eh_region_2): Merge into ... (duplicate_eh_regions): ... here. Take copy_region argument, and copy only a sub-tree if asked. Simplify copying and fixup. (eh_region_outer_p): New. * except.h (duplicate_eh_regions): Update decl. (eh_region_outer_p): Declare. * omp-low.c (lower_omp_single): Fix eh region placement wrt OMP_RETURN. (lower_omp_master): Likewise. (lower_omp_ordered): Likewise. * tree-cfg.c (struct move_stmt_d): Add new_label_map. (move_stmt_r): Use it to remap labels. Handle recursion vs remap_decls_p properly. (move_block_to_fn): Pass in new_label_map. Remap RESX_EXPR. (find_outermost_region_in_block): New. (new_label_mapper): New. (move_sese_region_to_fn): Copy eh information to the new function properly. * tree-inline.c (copy_cfg_body): Update for new duplicate_eh_regions argument. * tree-pretty-print.c (dump_generic_node): Dump RESX_EXPR region number. From-SVN: r112283
-rw-r--r--gcc/ChangeLog28
-rw-r--r--gcc/except.c283
-rw-r--r--gcc/except.h4
-rw-r--r--gcc/omp-low.c9
-rw-r--r--gcc/tree-cfg.c147
-rw-r--r--gcc/tree-inline.c3
-rw-r--r--gcc/tree-pretty-print.c4
7 files changed, 345 insertions, 133 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 1f5c7e8..1f564ad 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,31 @@
+2006-03-22 Richard Henderson <rth@redhat.com>
+
+ PR middle-end/26084
+ * except.c (duplicate_eh_regions_0): New.
+ (duplicate_eh_region_1): Duplicate the children of the node as
+ well as the node itself. Link them up properly.
+ (duplicate_eh_region_2): Merge into ...
+ (duplicate_eh_regions): ... here. Take copy_region argument, and
+ copy only a sub-tree if asked. Simplify copying and fixup.
+ (eh_region_outer_p): New.
+ * except.h (duplicate_eh_regions): Update decl.
+ (eh_region_outer_p): Declare.
+ * omp-low.c (lower_omp_single): Fix eh region placement wrt OMP_RETURN.
+ (lower_omp_master): Likewise.
+ (lower_omp_ordered): Likewise.
+ * tree-cfg.c (struct move_stmt_d): Add new_label_map.
+ (move_stmt_r): Use it to remap labels. Handle recursion vs
+ remap_decls_p properly.
+ (move_block_to_fn): Pass in new_label_map. Remap RESX_EXPR.
+ (find_outermost_region_in_block): New.
+ (new_label_mapper): New.
+ (move_sese_region_to_fn): Copy eh information to the new function
+ properly.
+ * tree-inline.c (copy_cfg_body): Update for new duplicate_eh_regions
+ argument.
+ * tree-pretty-print.c (dump_generic_node): Dump RESX_EXPR region
+ number.
+
2006-03-22 Richard Sandiford <richard@codesourcery.com>
* doc/md.texi (-mshared): Mention that -mshared code can be linked
diff --git a/gcc/except.c b/gcc/except.c
index 7c0088e..01f1108 100644
--- a/gcc/except.c
+++ b/gcc/except.c
@@ -857,84 +857,145 @@ current_function_has_exception_handlers (void)
return false;
}
-static struct eh_region *
-duplicate_eh_region_1 (struct eh_region *o)
-{
- struct eh_region *n = ggc_alloc_cleared (sizeof (struct eh_region));
-
- *n = *o;
+/* A subroutine of duplicate_eh_regions. Search the region tree under O
+ for the miniumum and maximum region numbers. Update *MIN and *MAX. */
- n->region_number = o->region_number + cfun->eh->last_region_number;
- VEC_replace (eh_region, cfun->eh->region_array, n->region_number, n);
- gcc_assert (!o->aka);
+static void
+duplicate_eh_regions_0 (eh_region o, int *min, int *max)
+{
+ if (o->region_number < *min)
+ *min = o->region_number;
+ if (o->region_number > *max)
+ *max = o->region_number;
- return n;
+ if (o->inner)
+ {
+ o = o->inner;
+ duplicate_eh_regions_0 (o, min, max);
+ while (o->next_peer)
+ {
+ o = o->next_peer;
+ duplicate_eh_regions_0 (o, min, max);
+ }
+ }
}
-static void
-duplicate_eh_region_2 (struct eh_region *o, struct eh_region **n_array,
- struct eh_region *prev_try)
+/* A subroutine of duplicate_eh_regions. Copy the region tree under OLD.
+ Root it at OUTER, and apply EH_OFFSET to the region number. Don't worry
+ about the other internal pointers just yet, just the tree-like pointers. */
+
+static eh_region
+duplicate_eh_regions_1 (eh_region old, eh_region outer, int eh_offset)
{
- struct eh_region *n = n_array[o->region_number];
+ eh_region ret, n;
- switch (n->type)
- {
- case ERT_TRY:
- if (o->u.try.catch)
- n->u.try.catch = n_array[o->u.try.catch->region_number];
- if (o->u.try.last_catch)
- n->u.try.last_catch = n_array[o->u.try.last_catch->region_number];
- break;
+ ret = n = ggc_alloc (sizeof (struct eh_region));
- case ERT_CATCH:
- if (o->u.catch.next_catch)
- n->u.catch.next_catch = n_array[o->u.catch.next_catch->region_number];
- if (o->u.catch.prev_catch)
- n->u.catch.prev_catch = n_array[o->u.catch.prev_catch->region_number];
- break;
+ *n = *old;
+ n->outer = outer;
+ gcc_assert (!old->aka);
- case ERT_CLEANUP:
- if (o->u.cleanup.prev_try)
- n->u.cleanup.prev_try = n_array[o->u.cleanup.prev_try->region_number];
- else
- n->u.cleanup.prev_try = prev_try;
- break;
+ n->region_number += eh_offset;
+ VEC_replace (eh_region, cfun->eh->region_array, n->region_number, n);
- default:
- break;
+ if (old->inner)
+ {
+ old = old->inner;
+ n = n->inner = duplicate_eh_regions_1 (old, ret, eh_offset);
+ while (old->next_peer)
+ {
+ old = old->next_peer;
+ n = n->next_peer = duplicate_eh_regions_1 (old, ret, eh_offset);
+ }
}
- if (o->outer)
- n->outer = n_array[o->outer->region_number];
- if (o->inner)
- n->inner = n_array[o->inner->region_number];
- if (o->next_peer)
- n->next_peer = n_array[o->next_peer->region_number];
+ return ret;
}
-/* Duplicate the EH regions of IFUN into current function, root the tree in
- OUTER_REGION and remap labels using MAP callback. */
+/* Duplicate the EH regions of IFUN, rootted at COPY_REGION, into current
+ function and root the tree below OUTER_REGION. Remap labels using MAP
+ callback. The special case of COPY_REGION of 0 means all regions. */
+
int
duplicate_eh_regions (struct function *ifun, duplicate_eh_regions_map map,
- void *data, int outer_region)
+ void *data, int copy_region, int outer_region)
{
- int ifun_last_region_number = ifun->eh->last_region_number;
- struct eh_region **n_array, *root, *cur, *prev_try;
- int i;
+ eh_region cur, prev_try, outer, *splice;
+ int i, min_region, max_region, eh_offset, cfun_last_region_number;
+ int num_regions;
- if (ifun_last_region_number == 0 || !ifun->eh->region_tree)
+ if (!ifun->eh->region_tree)
return 0;
- n_array = xcalloc (ifun_last_region_number + 1, sizeof (*n_array));
+ /* Find the range of region numbers to be copied. The interface we
+ provide here mandates a single offset to find new number from old,
+ which means we must look at the numbers present, instead of the
+ count or something else. */
+ if (copy_region > 0)
+ {
+ min_region = INT_MAX;
+ max_region = 0;
+
+ cur = VEC_index (eh_region, ifun->eh->region_array, copy_region);
+ duplicate_eh_regions_0 (cur, &min_region, &max_region);
+ }
+ else
+ min_region = 1, max_region = ifun->eh->last_region_number;
+ num_regions = max_region - min_region + 1;
+ cfun_last_region_number = cfun->eh->last_region_number;
+ eh_offset = cfun_last_region_number + 1 - min_region;
+
+ /* If we've not yet created a region array, do so now. */
VEC_safe_grow (eh_region, gc, cfun->eh->region_array,
- cfun->eh->last_region_number + 1 + ifun_last_region_number);
+ cfun_last_region_number + 1 + num_regions);
+ cfun->eh->last_region_number = max_region + eh_offset;
- /* We might've created new cfun->eh->region_array so zero out nonexisting region 0. */
+ /* We may have just allocated the array for the first time.
+ Make sure that element zero is null. */
VEC_replace (eh_region, cfun->eh->region_array, 0, 0);
- for (i = cfun->eh->last_region_number + 1;
- i < cfun->eh->last_region_number + 1 + ifun_last_region_number; i++)
- VEC_replace (eh_region, cfun->eh->region_array, i, 0);
+ /* Zero all entries in the range allocated. */
+ memset (VEC_address (eh_region, cfun->eh->region_array)
+ + cfun_last_region_number + 1, 0, num_regions);
+
+ /* Locate the spot at which to insert the new tree. */
+ if (outer_region > 0)
+ {
+ outer = VEC_index (eh_region, cfun->eh->region_array, outer_region);
+ splice = &outer->inner;
+ }
+ else
+ {
+ outer = NULL;
+ splice = &cfun->eh->region_tree;
+ }
+ while (*splice)
+ splice = &(*splice)->next_peer;
+
+ /* Copy all the regions in the subtree. */
+ if (copy_region > 0)
+ {
+ cur = VEC_index (eh_region, ifun->eh->region_array, copy_region);
+ *splice = duplicate_eh_regions_1 (cur, outer, eh_offset);
+ }
+ else
+ {
+ eh_region n;
+
+ cur = ifun->eh->region_tree;
+ *splice = n = duplicate_eh_regions_1 (cur, outer, eh_offset);
+ while (cur->next_peer)
+ {
+ cur = cur->next_peer;
+ n = n->next_peer = duplicate_eh_regions_1 (cur, outer, eh_offset);
+ }
+ }
+
+ /* Remap all the labels in the new regions. */
+ for (i = cfun_last_region_number + 1;
+ VEC_iterate (eh_region, cfun->eh->region_array, i, cur); ++i)
+ if (cur && cur->tree_label)
+ cur->tree_label = map (cur->tree_label, data);
/* Search for the containing ERT_TRY region to fix up
the prev_try short-cuts for ERT_CLEANUP regions. */
@@ -945,67 +1006,77 @@ duplicate_eh_regions (struct function *ifun, duplicate_eh_regions_map map,
prev_try = prev_try->outer)
;
- for (i = 1; i <= ifun_last_region_number; ++i)
- {
- cur = VEC_index (eh_region, ifun->eh->region_array, i);
- if (!cur || cur->region_number != i)
- continue;
- n_array[i] = duplicate_eh_region_1 (cur);
- if (cur->tree_label)
- {
- tree newlabel = map (cur->tree_label, data);
- n_array[i]->tree_label = newlabel;
- }
- else
- n_array[i]->tree_label = NULL;
- }
- for (i = 1; i <= ifun_last_region_number; ++i)
+ /* Remap all of the internal catch and cleanup linkages. Since we
+ duplicate entire subtrees, all of the referenced regions will have
+ been copied too. And since we renumbered them as a block, a simple
+ bit of arithmetic finds us the index for the replacement region. */
+ for (i = cfun_last_region_number + 1;
+ VEC_iterate (eh_region, cfun->eh->region_array, i, cur); ++i)
{
- cur = VEC_index (eh_region, ifun->eh->region_array, i);
- if (!cur || cur->region_number != i)
+ if (cur == NULL)
continue;
- duplicate_eh_region_2 (cur, n_array, prev_try);
- }
- root = n_array[ifun->eh->region_tree->region_number];
- gcc_assert (root->outer == NULL);
- if (outer_region > 0)
- {
- struct eh_region *cur
- = VEC_index (eh_region, cfun->eh->region_array, outer_region);
- struct eh_region *p = cur->inner;
+#define REMAP(REG) \
+ (REG) = VEC_index (eh_region, cfun->eh->region_array, \
+ (REG)->region_number + eh_offset)
- if (p)
+ switch (cur->type)
{
- while (p->next_peer)
- p = p->next_peer;
- p->next_peer = root;
- }
- else
- cur->inner = root;
- for (i = 1; i <= ifun_last_region_number; ++i)
- if (n_array[i] && n_array[i]->outer == NULL)
- n_array[i]->outer = cur;
- }
- else
- {
- struct eh_region *p = cfun->eh->region_tree;
- if (p)
- {
- while (p->next_peer)
- p = p->next_peer;
- p->next_peer = root;
+ case ERT_TRY:
+ if (cur->u.try.catch)
+ REMAP (cur->u.try.catch);
+ if (cur->u.try.last_catch)
+ REMAP (cur->u.try.last_catch);
+ break;
+
+ case ERT_CATCH:
+ if (cur->u.catch.next_catch)
+ REMAP (cur->u.catch.next_catch);
+ if (cur->u.catch.prev_catch)
+ REMAP (cur->u.catch.prev_catch);
+ break;
+
+ case ERT_CLEANUP:
+ if (cur->u.cleanup.prev_try)
+ REMAP (cur->u.cleanup.prev_try);
+ else
+ cur->u.cleanup.prev_try = prev_try;
+ break;
+
+ default:
+ break;
}
- else
- cfun->eh->region_tree = root;
+
+#undef REMAP
}
- free (n_array);
+ return eh_offset;
+}
- i = cfun->eh->last_region_number;
- cfun->eh->last_region_number = i + ifun_last_region_number;
+/* Return true if REGION_A is outer to REGION_B in IFUN. */
- return i;
+bool
+eh_region_outer_p (struct function *ifun, int region_a, int region_b)
+{
+ struct eh_region *rp_a, *rp_b;
+
+ gcc_assert (ifun->eh->last_region_number > 0);
+ gcc_assert (ifun->eh->region_tree);
+
+ rp_a = VEC_index (eh_region, ifun->eh->region_array, region_a);
+ rp_b = VEC_index (eh_region, ifun->eh->region_array, region_b);
+ gcc_assert (rp_a != NULL);
+ gcc_assert (rp_b != NULL);
+
+ do
+ {
+ if (rp_a == rp_b)
+ return true;
+ rp_b = rp_b->outer;
+ }
+ while (rp_b);
+
+ return false;
}
static int
diff --git a/gcc/except.h b/gcc/except.h
index 46914d4..5b28296 100644
--- a/gcc/except.h
+++ b/gcc/except.h
@@ -82,7 +82,8 @@ extern rtx expand_builtin_extend_pointer (tree);
extern rtx get_exception_pointer (struct function *);
extern rtx get_exception_filter (struct function *);
typedef tree (*duplicate_eh_regions_map) (tree, void *);
-extern int duplicate_eh_regions (struct function *, duplicate_eh_regions_map, void *, int);
+extern int duplicate_eh_regions (struct function *, duplicate_eh_regions_map,
+ void *, int, int);
extern void sjlj_emit_function_exit_after (rtx);
extern void default_init_unwind_resume_libfunc (void);
@@ -106,6 +107,7 @@ extern void collect_eh_region_array (void);
extern void expand_resx_expr (tree);
extern void verify_eh_tree (struct function *);
extern void dump_eh_tree (FILE *, struct function *);
+extern bool eh_region_outer_p (struct function *, int, int);
/* tree-eh.c */
extern void add_stmt_to_eh_region_fn (struct function *, tree, int);
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index 65f7151..41b4093 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -3464,6 +3464,9 @@ lower_omp_sections (tree *stmt_p, omp_context *ctx)
new_body = alloc_stmt_list ();
append_to_statement_list (ilist, &new_body);
append_to_statement_list (stmt, &new_body);
+ /* ??? The OMP_RETURN doesn't logically belong here, but in
+ expand_omp_sections we expect this marker to be where the
+ individual sections join after completing the loop. */
append_to_statement_list (region_exit, &new_body);
append_to_statement_list (olist, &new_body);
append_to_statement_list (dlist, &new_body);
@@ -3610,9 +3613,9 @@ lower_omp_single (tree *stmt_p, omp_context *ctx)
lower_omp_single_simple (single_stmt, &BIND_EXPR_BODY (bind));
append_to_statement_list (dlist, &BIND_EXPR_BODY (bind));
+ maybe_catch_exception (&BIND_EXPR_BODY (bind));
t = make_node (OMP_RETURN_EXPR);
append_to_statement_list (t, &BIND_EXPR_BODY (bind));
- maybe_catch_exception (&BIND_EXPR_BODY (bind));
pop_gimplify_context (bind);
BIND_EXPR_VARS (bind) = chainon (BIND_EXPR_VARS (bind), ctx->block_vars);
@@ -3647,9 +3650,9 @@ lower_omp_master (tree *stmt_p, omp_context *ctx)
x = build1 (LABEL_EXPR, void_type_node, lab);
gimplify_and_add (x, &BIND_EXPR_BODY (bind));
+ maybe_catch_exception (&BIND_EXPR_BODY (bind));
x = make_node (OMP_RETURN_EXPR);
append_to_statement_list (x, &BIND_EXPR_BODY (bind));
- maybe_catch_exception (&BIND_EXPR_BODY (bind));
pop_gimplify_context (bind);
BIND_EXPR_VARS (bind) = chainon (BIND_EXPR_VARS (bind), ctx->block_vars);
@@ -3683,9 +3686,9 @@ lower_omp_ordered (tree *stmt_p, omp_context *ctx)
x = built_in_decls[BUILT_IN_GOMP_ORDERED_END];
x = build_function_call_expr (x, NULL);
gimplify_and_add (x, &BIND_EXPR_BODY (bind));
+ maybe_catch_exception (&BIND_EXPR_BODY (bind));
x = make_node (OMP_RETURN_EXPR);
append_to_statement_list (x, &BIND_EXPR_BODY (bind));
- maybe_catch_exception (&BIND_EXPR_BODY (bind));
pop_gimplify_context (bind);
BIND_EXPR_VARS (bind) = chainon (BIND_EXPR_VARS (bind), ctx->block_vars);
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. */
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 8d258ff..3e35842 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -924,7 +924,8 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency,
if (id->transform_new_cfg)
init_eh_for_function ();
id->eh_region_offset
- = duplicate_eh_regions (cfun_to_copy, remap_decl_1, id, id->eh_region);
+ = duplicate_eh_regions (cfun_to_copy, remap_decl_1, id,
+ 0, id->eh_region);
}
/* Use aux pointers to map the original blocks to copy. */
FOR_EACH_BB_FN (bb, cfun_to_copy)
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index 23bea83..a8a33a5 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -1557,8 +1557,8 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
break;
case RESX_EXPR:
- pp_string (buffer, "resx");
- /* ??? Any sensible way to present the eh region? */
+ pp_string (buffer, "resx ");
+ dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
break;
case ASM_EXPR: