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
......
...@@ -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);
if (p->remap_decls_p p->remap_decls_p = save_remap_decls_p;
&& DECL_P (*tp) }
&& DECL_CONTEXT (*tp) == p->from_context) 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); DECL_CONTEXT (t) = p->to_context;
f->unexpanded_var_list = tree_cons (0, *tp, f->unexpanded_var_list);
/* Mark *TP to be removed from the original function, if (TREE_CODE (t) == VAR_DECL)
otherwise it will be given a DECL_RTL when the original {
function is expanded. */ struct function *f = DECL_STRUCT_FUNCTION (p->to_context);
bitmap_set_bit (p->vars_to_remove, DECL_UID (*tp)); 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; 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);
}
}
}
/* 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 /* 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