Commit fad41cd7 by Richard Henderson Committed by Richard Henderson

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
parent ee51e035
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> 2006-03-22 Richard Sandiford <richard@codesourcery.com>
* doc/md.texi (-mshared): Mention that -mshared code can be linked * doc/md.texi (-mshared): Mention that -mshared code can be linked
......
...@@ -857,84 +857,145 @@ current_function_has_exception_handlers (void) ...@@ -857,84 +857,145 @@ current_function_has_exception_handlers (void)
return false; return false;
} }
static struct eh_region * /* A subroutine of duplicate_eh_regions. Search the region tree under O
duplicate_eh_region_1 (struct eh_region *o) for the miniumum and maximum region numbers. Update *MIN and *MAX. */
{
struct eh_region *n = ggc_alloc_cleared (sizeof (struct eh_region));
*n = *o;
n->region_number = o->region_number + cfun->eh->last_region_number; static void
VEC_replace (eh_region, cfun->eh->region_array, n->region_number, n); duplicate_eh_regions_0 (eh_region o, int *min, int *max)
gcc_assert (!o->aka); {
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 /* A subroutine of duplicate_eh_regions. Copy the region tree under OLD.
duplicate_eh_region_2 (struct eh_region *o, struct eh_region **n_array, Root it at OUTER, and apply EH_OFFSET to the region number. Don't worry
struct eh_region *prev_try) 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) ret = n = ggc_alloc (sizeof (struct eh_region));
{
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;
case ERT_CATCH: *n = *old;
if (o->u.catch.next_catch) n->outer = outer;
n->u.catch.next_catch = n_array[o->u.catch.next_catch->region_number]; gcc_assert (!old->aka);
if (o->u.catch.prev_catch)
n->u.catch.prev_catch = n_array[o->u.catch.prev_catch->region_number];
break;
case ERT_CLEANUP: n->region_number += eh_offset;
if (o->u.cleanup.prev_try) VEC_replace (eh_region, cfun->eh->region_array, n->region_number, n);
n->u.cleanup.prev_try = n_array[o->u.cleanup.prev_try->region_number];
else
n->u.cleanup.prev_try = prev_try;
break;
default: if (old->inner)
break; {
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) return ret;
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];
} }
/* Duplicate the EH regions of IFUN into current function, root the tree in /* Duplicate the EH regions of IFUN, rootted at COPY_REGION, into current
OUTER_REGION and remap labels using MAP callback. */ 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 int
duplicate_eh_regions (struct function *ifun, duplicate_eh_regions_map map, 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; eh_region cur, prev_try, outer, *splice;
struct eh_region **n_array, *root, *cur, *prev_try; int i, min_region, max_region, eh_offset, cfun_last_region_number;
int i; int num_regions;
if (ifun_last_region_number == 0 || !ifun->eh->region_tree) if (!ifun->eh->region_tree)
return 0; 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, 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); VEC_replace (eh_region, cfun->eh->region_array, 0, 0);
for (i = cfun->eh->last_region_number + 1; /* Zero all entries in the range allocated. */
i < cfun->eh->last_region_number + 1 + ifun_last_region_number; i++) memset (VEC_address (eh_region, cfun->eh->region_array)
VEC_replace (eh_region, cfun->eh->region_array, i, 0); + 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 /* Search for the containing ERT_TRY region to fix up
the prev_try short-cuts for ERT_CLEANUP regions. */ the prev_try short-cuts for ERT_CLEANUP regions. */
...@@ -945,67 +1006,77 @@ duplicate_eh_regions (struct function *ifun, duplicate_eh_regions_map map, ...@@ -945,67 +1006,77 @@ duplicate_eh_regions (struct function *ifun, duplicate_eh_regions_map map,
prev_try = prev_try->outer) prev_try = prev_try->outer)
; ;
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 == NULL)
if (!cur || cur->region_number != i)
continue; 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)
{
cur = VEC_index (eh_region, ifun->eh->region_array, i);
if (!cur || cur->region_number != i)
continue;
duplicate_eh_region_2 (cur, n_array, prev_try);
}
root = n_array[ifun->eh->region_tree->region_number]; #define REMAP(REG) \
gcc_assert (root->outer == NULL); (REG) = VEC_index (eh_region, cfun->eh->region_array, \
if (outer_region > 0) (REG)->region_number + eh_offset)
{
struct eh_region *cur
= VEC_index (eh_region, cfun->eh->region_array, outer_region);
struct eh_region *p = cur->inner;
if (p) switch (cur->type)
{ {
while (p->next_peer) case ERT_TRY:
p = p->next_peer; if (cur->u.try.catch)
p->next_peer = root; REMAP (cur->u.try.catch);
} if (cur->u.try.last_catch)
else REMAP (cur->u.try.last_catch);
cur->inner = root; break;
for (i = 1; i <= ifun_last_region_number; ++i)
if (n_array[i] && n_array[i]->outer == NULL) case ERT_CATCH:
n_array[i]->outer = cur; 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 else
{ cur->u.cleanup.prev_try = prev_try;
struct eh_region *p = cfun->eh->region_tree; break;
if (p)
{ default:
while (p->next_peer) break;
p = p->next_peer;
p->next_peer = root;
} }
else
cfun->eh->region_tree = root; #undef REMAP
} }
free (n_array); return eh_offset;
}
i = cfun->eh->last_region_number; /* Return true if REGION_A is outer to REGION_B in IFUN. */
cfun->eh->last_region_number = i + ifun_last_region_number;
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 static int
......
...@@ -82,7 +82,8 @@ extern rtx expand_builtin_extend_pointer (tree); ...@@ -82,7 +82,8 @@ extern rtx expand_builtin_extend_pointer (tree);
extern rtx get_exception_pointer (struct function *); extern rtx get_exception_pointer (struct function *);
extern rtx get_exception_filter (struct function *); extern rtx get_exception_filter (struct function *);
typedef tree (*duplicate_eh_regions_map) (tree, void *); 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 sjlj_emit_function_exit_after (rtx);
extern void default_init_unwind_resume_libfunc (void); extern void default_init_unwind_resume_libfunc (void);
...@@ -106,6 +107,7 @@ extern void collect_eh_region_array (void); ...@@ -106,6 +107,7 @@ extern void collect_eh_region_array (void);
extern void expand_resx_expr (tree); extern void expand_resx_expr (tree);
extern void verify_eh_tree (struct function *); extern void verify_eh_tree (struct function *);
extern void dump_eh_tree (FILE *, struct function *); extern void dump_eh_tree (FILE *, struct function *);
extern bool eh_region_outer_p (struct function *, int, int);
/* tree-eh.c */ /* tree-eh.c */
extern void add_stmt_to_eh_region_fn (struct function *, tree, int); extern void add_stmt_to_eh_region_fn (struct function *, tree, int);
......
...@@ -3464,6 +3464,9 @@ lower_omp_sections (tree *stmt_p, omp_context *ctx) ...@@ -3464,6 +3464,9 @@ lower_omp_sections (tree *stmt_p, omp_context *ctx)
new_body = alloc_stmt_list (); new_body = alloc_stmt_list ();
append_to_statement_list (ilist, &new_body); append_to_statement_list (ilist, &new_body);
append_to_statement_list (stmt, &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 (region_exit, &new_body);
append_to_statement_list (olist, &new_body); append_to_statement_list (olist, &new_body);
append_to_statement_list (dlist, &new_body); append_to_statement_list (dlist, &new_body);
...@@ -3610,9 +3613,9 @@ lower_omp_single (tree *stmt_p, omp_context *ctx) ...@@ -3610,9 +3613,9 @@ lower_omp_single (tree *stmt_p, omp_context *ctx)
lower_omp_single_simple (single_stmt, &BIND_EXPR_BODY (bind)); lower_omp_single_simple (single_stmt, &BIND_EXPR_BODY (bind));
append_to_statement_list (dlist, &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); t = make_node (OMP_RETURN_EXPR);
append_to_statement_list (t, &BIND_EXPR_BODY (bind)); append_to_statement_list (t, &BIND_EXPR_BODY (bind));
maybe_catch_exception (&BIND_EXPR_BODY (bind));
pop_gimplify_context (bind); pop_gimplify_context (bind);
BIND_EXPR_VARS (bind) = chainon (BIND_EXPR_VARS (bind), ctx->block_vars); 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) ...@@ -3647,9 +3650,9 @@ lower_omp_master (tree *stmt_p, omp_context *ctx)
x = build1 (LABEL_EXPR, void_type_node, lab); x = build1 (LABEL_EXPR, void_type_node, lab);
gimplify_and_add (x, &BIND_EXPR_BODY (bind)); gimplify_and_add (x, &BIND_EXPR_BODY (bind));
maybe_catch_exception (&BIND_EXPR_BODY (bind));
x = make_node (OMP_RETURN_EXPR); x = make_node (OMP_RETURN_EXPR);
append_to_statement_list (x, &BIND_EXPR_BODY (bind)); append_to_statement_list (x, &BIND_EXPR_BODY (bind));
maybe_catch_exception (&BIND_EXPR_BODY (bind));
pop_gimplify_context (bind); pop_gimplify_context (bind);
BIND_EXPR_VARS (bind) = chainon (BIND_EXPR_VARS (bind), ctx->block_vars); 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) ...@@ -3683,9 +3686,9 @@ lower_omp_ordered (tree *stmt_p, omp_context *ctx)
x = built_in_decls[BUILT_IN_GOMP_ORDERED_END]; x = built_in_decls[BUILT_IN_GOMP_ORDERED_END];
x = build_function_call_expr (x, NULL); x = build_function_call_expr (x, NULL);
gimplify_and_add (x, &BIND_EXPR_BODY (bind)); gimplify_and_add (x, &BIND_EXPR_BODY (bind));
maybe_catch_exception (&BIND_EXPR_BODY (bind));
x = make_node (OMP_RETURN_EXPR); x = make_node (OMP_RETURN_EXPR);
append_to_statement_list (x, &BIND_EXPR_BODY (bind)); append_to_statement_list (x, &BIND_EXPR_BODY (bind));
maybe_catch_exception (&BIND_EXPR_BODY (bind));
pop_gimplify_context (bind); pop_gimplify_context (bind);
BIND_EXPR_VARS (bind) = chainon (BIND_EXPR_VARS (bind), ctx->block_vars); BIND_EXPR_VARS (bind) = chainon (BIND_EXPR_VARS (bind), ctx->block_vars);
......
...@@ -4591,6 +4591,7 @@ struct move_stmt_d ...@@ -4591,6 +4591,7 @@ struct move_stmt_d
tree from_context; tree from_context;
tree to_context; tree to_context;
bitmap vars_to_remove; bitmap vars_to_remove;
htab_t new_label_map;
bool remap_decls_p; bool remap_decls_p;
}; };
...@@ -4599,39 +4600,62 @@ struct move_stmt_d ...@@ -4599,39 +4600,62 @@ struct move_stmt_d
variable referenced in *TP. */ variable referenced in *TP. */
static tree 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; 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)))) if (p->block && IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (t))))
TREE_BLOCK (*tp) = p->block; 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 /* Do not remap variables inside OMP directives. Variables
referenced in clauses and directive header belong to the referenced in clauses and directive header belong to the
parent function and should not be moved into the child parent function and should not be moved into the child
function. */ function. */
bool save_remap_decls_p = p->remap_decls_p;
p->remap_decls_p = false; p->remap_decls_p = false;
*walk_subtrees = 0;
walk_tree (&OMP_BODY (t), move_stmt_r, p, NULL);
p->remap_decls_p = save_remap_decls_p;
}
else if (DECL_P (t) && DECL_CONTEXT (t) == p->from_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 (p->remap_decls_p DECL_CONTEXT (t) = p->to_context;
&& DECL_P (*tp) }
&& DECL_CONTEXT (*tp) == p->from_context) else if (p->remap_decls_p)
{ {
DECL_CONTEXT (*tp) = p->to_context; DECL_CONTEXT (t) = p->to_context;
if (TREE_CODE (*tp) == VAR_DECL) if (TREE_CODE (t) == VAR_DECL)
{ {
struct function *f = DECL_STRUCT_FUNCTION (p->to_context); struct function *f = DECL_STRUCT_FUNCTION (p->to_context);
f->unexpanded_var_list = tree_cons (0, *tp, f->unexpanded_var_list); f->unexpanded_var_list
= tree_cons (0, t, f->unexpanded_var_list);
/* Mark *TP to be removed from the original function, /* Mark T to be removed from the original function,
otherwise it will be given a DECL_RTL when the original otherwise it will be given a DECL_RTL when the
function is expanded. */ original function is expanded. */
bitmap_set_bit (p->vars_to_remove, DECL_UID (*tp)); bitmap_set_bit (p->vars_to_remove, DECL_UID (t));
}
} }
} }
else if (TYPE_P (t))
*walk_subtrees = 0;
return NULL_TREE; return NULL_TREE;
} }
...@@ -4650,7 +4674,7 @@ move_stmt_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, void *data) ...@@ -4650,7 +4674,7 @@ move_stmt_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, void *data)
static void static void
move_block_to_fn (struct function *dest_cfun, basic_block bb, move_block_to_fn (struct function *dest_cfun, basic_block bb,
basic_block after, bool update_edge_count_p, 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; struct control_flow_graph *cfg;
edge_iterator ei; edge_iterator ei;
...@@ -4701,10 +4725,12 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb, ...@@ -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)) for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
{ {
tree stmt = bsi_stmt (si); tree stmt = bsi_stmt (si);
int region;
d.from_context = cfun->decl; d.from_context = cfun->decl;
d.to_context = dest_cfun->decl; d.to_context = dest_cfun->decl;
d.remap_decls_p = true; d.remap_decls_p = true;
d.new_label_map = new_label_map;
if (TREE_BLOCK (stmt)) if (TREE_BLOCK (stmt))
d.block = DECL_INITIAL (dest_cfun->decl); d.block = DECL_INITIAL (dest_cfun->decl);
...@@ -4736,11 +4762,66 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb, ...@@ -4736,11 +4762,66 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb,
if (uid >= dest_cfun->last_label_uid) if (uid >= dest_cfun->last_label_uid)
dest_cfun->last_label_uid = uid + 1; 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); 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;
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 /* 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 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, ...@@ -4763,11 +4844,12 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
VEC(basic_block,heap) *bbs; VEC(basic_block,heap) *bbs;
basic_block after, bb, *entry_pred, *exit_succ; basic_block after, bb, *entry_pred, *exit_succ;
struct function *saved_cfun; struct function *saved_cfun;
int *entry_flag, *exit_flag; int *entry_flag, *exit_flag, eh_offset;
unsigned i, num_entry_edges, num_exit_edges; unsigned i, num_entry_edges, num_exit_edges;
edge e; edge e;
edge_iterator ei; edge_iterator ei;
bitmap vars_to_remove; bitmap vars_to_remove;
htab_t new_label_map;
saved_cfun = cfun; saved_cfun = cfun;
...@@ -4813,7 +4895,28 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb, ...@@ -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. */ /* Switch context to the child function to initialize DEST_FN's CFG. */
gcc_assert (dest_cfun->cfg == NULL); gcc_assert (dest_cfun->cfg == NULL);
cfun = dest_cfun; cfun = dest_cfun;
init_empty_tree_cfg (); 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; cfun = saved_cfun;
/* Move blocks from BBS into DEST_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, ...@@ -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 /* No need to update edge counts on the last block. It has
already been updated earlier when we detached the region from already been updated earlier when we detached the region from
the original CFG. */ 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; after = bb;
} }
if (new_label_map)
htab_delete (new_label_map);
/* Remove the variables marked in VARS_TO_REMOVE from /* Remove the variables marked in VARS_TO_REMOVE from
CFUN->UNEXPANDED_VAR_LIST. Otherwise, they will be given a CFUN->UNEXPANDED_VAR_LIST. Otherwise, they will be given a
DECL_RTL in the context of CFUN. */ DECL_RTL in the context of CFUN. */
......
...@@ -924,7 +924,8 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency, ...@@ -924,7 +924,8 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency,
if (id->transform_new_cfg) if (id->transform_new_cfg)
init_eh_for_function (); init_eh_for_function ();
id->eh_region_offset 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. */ /* Use aux pointers to map the original blocks to copy. */
FOR_EACH_BB_FN (bb, cfun_to_copy) FOR_EACH_BB_FN (bb, cfun_to_copy)
......
...@@ -1557,8 +1557,8 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, ...@@ -1557,8 +1557,8 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
break; break;
case RESX_EXPR: case RESX_EXPR:
pp_string (buffer, "resx"); pp_string (buffer, "resx ");
/* ??? Any sensible way to present the eh region? */ dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
break; break;
case ASM_EXPR: case ASM_EXPR:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment