+2008-06-27 Jakub Jelinek <jakub@redhat.com>
+
+ PR debug/36617
+ * tree-cfg.c (struct move_stmt_d): Replace block field with
+ orig_block and new_block fields.
+ (move_stmt_r): Only set TREE_BLOCK to p->new_block if
+ if it used to be NULL, p->orig_block or if p->orig_block is NULL.
+ (move_block_to_fn): Replace vars_map and new_label_map arguments
+ with struct move_stmt_d pointer.
+ (replace_block_vars_by_duplicates): New function.
+ (move_sese_region_to_fn): Add ORIG_BLOCK argument. Adjust
+ move_block_to_fn caller. If ORIG_BLOCK is non-NULL, move over
+ all subblocks of ORIG_BLOCK to the new function. Call
+ replace_block_vars_by_duplicates.
+ * tree-flow.h (move_sese_region_to_fn): Adjust prototype.
+ * omp-low.c (expand_omp_taskreg): Set TREE_USED on DECL_INITIAL
+ BLOCK of the new function. Adjust move_sese_region_to_fn caller.
+ Prune vars with original DECL_CONTEXT from child_cfun->local_decls.
+ (expand_omp): Temporarily set input_location to the location of
+ region's controlling stmt.
+ (lower_omp_sections, lower_omp_for): Add a BLOCK into outermost
+ BIND_EXPR, push ctx->block_vars and gimplification vars into
+ the BIND_EXPR and its block's BLOCK_VARS instead of directly
+ into dest function.
+ (lower_omp_single): Set TREE_USED on the BIND_EXPR's BLOCK if
+ there are any BLOCK_VARS.
+ (lower_omp_taskreg): Set BLOCK on a BIND_EXPR containing the
+ OMP_PARALLEL or OMP_TASK stmt.
+ (lower_omp): Save and restore input_location around the lower_omp_1
+ call.
+
2008-06-27 Richard Guenther <rguenther@suse.de>
PR tree-optimization/36400
{
basic_block entry_bb, exit_bb, new_bb;
struct function *child_cfun;
- tree child_fn, block, t, ws_args;
+ tree child_fn, block, t, ws_args, *tp;
block_stmt_iterator si;
tree entry_stmt;
edge e;
block = DECL_INITIAL (child_fn);
BLOCK_VARS (block) = list2chain (child_cfun->local_decls);
DECL_SAVED_TREE (child_fn) = bb_stmt_list (single_succ (entry_bb));
+ TREE_USED (block) = 1;
/* Reset DECL_CONTEXT on function arguments. */
for (t = DECL_ARGUMENTS (child_fn); t; t = TREE_CHAIN (t))
init_ssa_operands ();
cfun->gimple_df->in_ssa_p = true;
pop_cfun ();
+ block = NULL_TREE;
}
- new_bb = move_sese_region_to_fn (child_cfun, entry_bb, exit_bb);
+ else
+ block = TREE_BLOCK (entry_stmt);
+
+ new_bb = move_sese_region_to_fn (child_cfun, entry_bb, exit_bb, block);
if (exit_bb)
single_succ_edge (new_bb)->flags = EDGE_FALLTHRU;
+ /* Remove non-local VAR_DECLs from child_cfun->local_decls list. */
+ for (tp = &child_cfun->local_decls; *tp; )
+ if (DECL_CONTEXT (TREE_VALUE (*tp)) != cfun->decl)
+ tp = &TREE_CHAIN (*tp);
+ else
+ *tp = TREE_CHAIN (*tp);
+
/* Inform the callgraph about the new function. */
DECL_STRUCT_FUNCTION (child_fn)->curr_properties
= cfun->curr_properties;
{
while (region)
{
+ location_t saved_location;
+
/* First, determine whether this is a combined parallel+workshare
region. */
if (region->type == OMP_PARALLEL)
if (region->inner)
expand_omp (region->inner);
+ saved_location = input_location;
+ if (EXPR_HAS_LOCATION (last_stmt (region->entry)))
+ input_location = EXPR_LOCATION (last_stmt (region->entry));
+
switch (region->type)
{
case OMP_PARALLEL:
expand_omp_atomic (region);
break;
-
default:
gcc_unreachable ();
}
+ input_location = saved_location;
region = region->next;
}
}
olist = NULL_TREE;
lower_reduction_clauses (OMP_SECTIONS_CLAUSES (stmt), &olist, ctx);
- pop_gimplify_context (NULL_TREE);
- record_vars_into (ctx->block_vars, ctx->cb.dst_fn);
-
- new_stmt = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL);
+ block = make_node (BLOCK);
+ new_stmt = build3 (BIND_EXPR, void_type_node, NULL, NULL, block);
TREE_SIDE_EFFECTS (new_stmt) = 1;
+ pop_gimplify_context (new_stmt);
+
+ BIND_EXPR_VARS (new_stmt)
+ = chainon (BIND_EXPR_VARS (new_stmt), ctx->block_vars);
+ BLOCK_VARS (block) = BIND_EXPR_VARS (new_stmt);
+ if (BLOCK_VARS (block))
+ TREE_USED (block) = 1;
+
new_body = alloc_stmt_list ();
append_to_statement_list (ilist, &new_body);
append_to_statement_list (stmt, &new_body);
BIND_EXPR_VARS (bind) = chainon (BIND_EXPR_VARS (bind), ctx->block_vars);
BLOCK_VARS (block) = BIND_EXPR_VARS (bind);
+ if (BLOCK_VARS (block))
+ TREE_USED (block) = 1;
}
static void
lower_omp_for (tree *stmt_p, omp_context *ctx)
{
- tree t, stmt, ilist, dlist, new_stmt, *body_p, *rhs_p;
+ tree t, stmt, ilist, dlist, new_stmt, block, *body_p, *rhs_p;
struct omp_for_data fd;
int i;
lower_omp (&OMP_FOR_PRE_BODY (stmt), ctx);
lower_omp (&OMP_FOR_BODY (stmt), ctx);
+ block = make_node (BLOCK);
+ new_stmt = build3 (BIND_EXPR, void_type_node, NULL, NULL, block);
+ TREE_SIDE_EFFECTS (new_stmt) = 1;
+ body_p = &BIND_EXPR_BODY (new_stmt);
+
/* Move declaration of temporaries in the loop body before we make
it go away. */
if (TREE_CODE (OMP_FOR_BODY (stmt)) == BIND_EXPR)
- record_vars_into (BIND_EXPR_VARS (OMP_FOR_BODY (stmt)), ctx->cb.dst_fn);
-
- new_stmt = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL);
- TREE_SIDE_EFFECTS (new_stmt) = 1;
- body_p = &BIND_EXPR_BODY (new_stmt);
+ BIND_EXPR_VARS (new_stmt)
+ = chainon (BIND_EXPR_VARS (new_stmt),
+ BIND_EXPR_VARS (OMP_FOR_BODY (stmt)));
/* The pre-body and input clauses go before the lowered OMP_FOR. */
ilist = NULL;
OMP_RETURN_NOWAIT (t) = fd.have_nowait;
append_to_statement_list (t, body_p);
- pop_gimplify_context (NULL_TREE);
- record_vars_into (ctx->block_vars, ctx->cb.dst_fn);
+ pop_gimplify_context (new_stmt);
+ BIND_EXPR_VARS (new_stmt)
+ = chainon (BIND_EXPR_VARS (new_stmt), ctx->block_vars);
+ BLOCK_VARS (block) = BIND_EXPR_VARS (new_stmt);
+ if (BLOCK_VARS (block))
+ TREE_USED (block) = 1;
OMP_FOR_BODY (stmt) = NULL_TREE;
OMP_FOR_PRE_BODY (stmt) = NULL_TREE;
/* Once all the expansions are done, sequence all the different
fragments inside OMP_TASKREG_BODY. */
- bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL);
- append_to_statement_list (ilist, &BIND_EXPR_BODY (bind));
+ bind = build3 (BIND_EXPR, void_type_node, NULL, NULL,
+ BIND_EXPR_BLOCK (par_bind));
+ TREE_SIDE_EFFECTS (bind) = 1;
new_body = alloc_stmt_list ();
OMP_TASKREG_BODY (stmt) = new_body;
append_to_statement_list (stmt, &BIND_EXPR_BODY (bind));
- append_to_statement_list (olist, &BIND_EXPR_BODY (bind));
+ if (ilist || olist)
+ {
+ append_to_statement_list (bind, &ilist);
+ append_to_statement_list (olist, &ilist);
+ bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL);
+ TREE_SIDE_EFFECTS (bind) = 1;
+ append_to_statement_list (ilist, &BIND_EXPR_BODY (bind));
+ }
*stmt_p = bind;
static void
lower_omp (tree *stmt_p, omp_context *ctx)
{
+ location_t saved_location = input_location;
lower_omp_1 (stmt_p, ctx, NULL);
+ input_location = saved_location;
}
\f
/* Main entry point. */
struct move_stmt_d
{
- tree block;
+ tree orig_block;
+ tree new_block;
tree from_context;
tree to_context;
struct pointer_map_t *vars_map;
};
/* Helper for move_block_to_fn. Set TREE_BLOCK in every expression
- contained in *TP and change the DECL_CONTEXT of every local
- variable referenced in *TP. */
+ contained in *TP if it has been ORIG_BLOCK previously and change the
+ DECL_CONTEXT of every local variable referenced in *TP. */
static tree
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
- && (EXPR_P (t) || GIMPLE_STMT_P (t)))
- TREE_BLOCK (t) = p->block;
+ if (EXPR_P (t) || GIMPLE_STMT_P (t))
+ {
+ tree block = TREE_BLOCK (t);
+ if (p->orig_block == NULL_TREE
+ || block == p->orig_block
+ || block == NULL_TREE)
+ TREE_BLOCK (t) = p->new_block;
+#ifdef ENABLE_CHECKING
+ else if (block != p->new_block)
+ {
+ while (block && block != p->orig_block)
+ block = BLOCK_SUPERCONTEXT (block);
+ gcc_assert (block);
+ }
+#endif
+ }
if (OMP_DIRECTIVE_P (t)
&& TREE_CODE (t) != OMP_RETURN
static void
move_block_to_fn (struct function *dest_cfun, basic_block bb,
basic_block after, bool update_edge_count_p,
- struct pointer_map_t *vars_map, htab_t new_label_map,
- int eh_offset)
+ struct move_stmt_d *d, int eh_offset)
{
struct control_flow_graph *cfg;
edge_iterator ei;
edge e;
block_stmt_iterator si;
- struct move_stmt_d d;
unsigned old_len, new_len;
tree phi, next_phi;
continue;
}
- SET_PHI_RESULT (phi, replace_ssa_name (op, vars_map, dest_cfun->decl));
+ SET_PHI_RESULT (phi,
+ replace_ssa_name (op, d->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));
+ SET_USE (use, replace_ssa_name (op, d->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_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.remap_decls_p = true;
- if (TREE_BLOCK (stmt))
- d.block = DECL_INITIAL (dest_cfun->decl);
-
- walk_tree (&stmt, move_stmt_r, &d, NULL);
+ walk_tree (&stmt, move_stmt_r, d, NULL);
if (TREE_CODE (stmt) == LABEL_EXPR)
{
return m->to;
}
+/* Change DECL_CONTEXT of all BLOCK_VARS in block, including
+ subblocks. */
+
+static void
+replace_block_vars_by_duplicates (tree block, struct pointer_map_t *vars_map,
+ tree to_context)
+{
+ tree *tp, t;
+
+ for (tp = &BLOCK_VARS (block); *tp; tp = &TREE_CHAIN (*tp))
+ {
+ t = *tp;
+ replace_by_duplicate_decl (&t, vars_map, to_context);
+ if (t != *tp)
+ {
+ if (TREE_CODE (*tp) == VAR_DECL && DECL_HAS_VALUE_EXPR_P (*tp))
+ {
+ SET_DECL_VALUE_EXPR (t, DECL_VALUE_EXPR (*tp));
+ DECL_HAS_VALUE_EXPR_P (t) = 1;
+ }
+ TREE_CHAIN (t) = TREE_CHAIN (*tp);
+ *tp = t;
+ }
+ }
+
+ for (block = BLOCK_SUBBLOCKS (block); block; block = BLOCK_CHAIN (block))
+ replace_block_vars_by_duplicates (block, vars_map, to_context);
+}
+
/* 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
single basic block in the original CFG and the new basic block is
is that ENTRY_BB should be the only entry point and it must
dominate EXIT_BB.
+ Change TREE_BLOCK of all statements in ORIG_BLOCK to the new
+ functions outermost BLOCK, move all subblocks of ORIG_BLOCK
+ to the new function.
+
All local variables referenced in the region are assumed to be in
the corresponding BLOCK_VARS and unexpanded variable lists
associated with DEST_CFUN. */
basic_block
move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
- basic_block exit_bb)
+ basic_block exit_bb, tree orig_block)
{
VEC(basic_block,heap) *bbs, *dom_bbs;
basic_block dom_entry = get_immediate_dominator (CDI_DOMINATORS, entry_bb);
htab_t new_label_map;
struct pointer_map_t *vars_map;
struct loop *loop = entry_bb->loop_father;
+ struct move_stmt_d d;
/* If ENTRY does not strictly dominate EXIT, this cannot be an SESE
region. */
gcc_assert (VEC_length (basic_block, bbs) >= 2);
after = dest_cfun->cfg->x_entry_block_ptr;
vars_map = pointer_map_create ();
+
+ memset (&d, 0, sizeof (d));
+ d.vars_map = vars_map;
+ d.from_context = cfun->decl;
+ d.to_context = dest_cfun->decl;
+ d.new_label_map = new_label_map;
+ d.remap_decls_p = true;
+ d.orig_block = orig_block;
+ d.new_block = DECL_INITIAL (dest_cfun->decl);
+
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_map,
- new_label_map, eh_offset);
+ move_block_to_fn (dest_cfun, bb, after, bb != exit_bb, &d, eh_offset);
after = bb;
}
+ /* Rewire BLOCK_SUBBLOCKS of orig_block. */
+ if (orig_block)
+ {
+ tree block;
+ gcc_assert (BLOCK_SUBBLOCKS (DECL_INITIAL (dest_cfun->decl))
+ == NULL_TREE);
+ BLOCK_SUBBLOCKS (DECL_INITIAL (dest_cfun->decl))
+ = BLOCK_SUBBLOCKS (orig_block);
+ for (block = BLOCK_SUBBLOCKS (orig_block);
+ block; block = BLOCK_CHAIN (block))
+ BLOCK_SUPERCONTEXT (block) = DECL_INITIAL (dest_cfun->decl);
+ BLOCK_SUBBLOCKS (orig_block) = NULL_TREE;
+ }
+
+ replace_block_vars_by_duplicates (DECL_INITIAL (dest_cfun->decl),
+ vars_map, dest_cfun->decl);
+
if (new_label_map)
htab_delete (new_label_map);
pointer_map_destroy (vars_map);
/* Data and Control Flow Analysis for Trees.
- Copyright (C) 2001, 2003, 2004, 2005, 2006, 2007
+ Copyright (C) 2001, 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@redhat.com>
extern void start_recording_case_labels (void);
extern void end_recording_case_labels (void);
extern basic_block move_sese_region_to_fn (struct function *, basic_block,
- basic_block);
+ basic_block, tree);
void remove_edge_and_dominated_blocks (edge);
void mark_virtual_ops_in_bb (basic_block);
+2008-06-27 Jakub Jelinek <jakub@redhat.com>
+
+ PR debug/36617
+ * testsuite/libgomp.c/debug-1.c: New test.
+
2008-06-19 Jakub Jelinek <jakub@redhat.com>
* testsuite/libgomp.c/nqueens-1.c: New test.
--- /dev/null
+/* PR debug/36617 */
+/* { dg-do run } */
+/* { dg-options "-g -fopenmp -O0" } */
+
+int
+f1 (void)
+{
+ int v1i, v1j, v1k, v1l = 0;
+ v1i = 6;
+ v1j = 8;
+ #pragma omp parallel private (v1k) firstprivate (v1j) shared (v1i) reduction (+:v1l)
+ {
+ v1k = v1i + v1j;
+ {
+ int v1m = 1;
+ v1l = v1m;
+ }
+ }
+ return v1l;
+}
+
+int v2k = 9;
+
+int
+f2 (void)
+{
+ int v2i = 6, v2j = 7;
+ #pragma omp single private (v2i) firstprivate (v2k)
+ {
+ int v2l = v2j + v2k;
+ v2i = 8;
+ v2k = 10;
+ v2j = v2l + v2i;
+ }
+ return v2i + v2j;
+}
+
+int
+f3 (void)
+{
+ int v3i = 6, v3j = 7, v3k = 9;
+ #pragma omp parallel
+ {
+ #pragma omp master
+ v3i++;
+ #pragma omp single private (v3i) firstprivate (v3k)
+ {
+ int v3l = v3j + v3k;
+ v3i = 8;
+ v3k = 10;
+ v3j = v3l + v3i;
+ }
+ #pragma omp atomic
+ v3k++;
+ }
+ return v3i + v3j;
+}
+
+int v4k = 9, v4l = 0;
+
+int
+f4 (void)
+{
+ int v4i = 6, v4j = 7, v4n = 0;
+ #pragma omp sections private (v4i) firstprivate (v4k) reduction (+:v4l)
+ {
+ #pragma omp section
+ {
+ int v4m = v4j + v4k;
+ v4i = 8;
+ v4k = 10;
+ v4l++;
+ v4n = v4m + v4i;
+ }
+ #pragma omp section
+ {
+ int v4o = v4j + v4k;
+ v4i = 10;
+ v4k = 11;
+ v4l++;
+ }
+ }
+ return v4i + v4j + v4l + v4n;
+}
+
+int
+f5 (void)
+{
+ int v5i = 6, v5j = 7, v5k = 9, v5l = 0, v5n = 0, v5p = 0;
+ #pragma omp parallel
+ {
+ #pragma omp master
+ v5p++;
+ #pragma omp sections private (v5i) firstprivate (v5k) reduction (+:v5l)
+ {
+ #pragma omp section
+ {
+ int v5m = v5j + v5k;
+ v5i = 8;
+ v5k = 10;
+ v5l++;
+ v5n = v5m + v5i;
+ }
+ #pragma omp section
+ {
+ int v5o = v5j + v5k;
+ v5i = 10;
+ v5k = 11;
+ v5l++;
+ }
+ }
+ }
+ return v5i + v5j + v5l + v5n + v5p;
+}
+
+int v6k = 9, v6l = 0;
+
+int
+f6 (void)
+{
+ int v6i = 6, v6j = 7, v6n = 0;
+ #pragma omp for private (v6i) firstprivate (v6k) reduction (+:v6l)
+ for (v6n = 0; v6n < 3; v6n++)
+ {
+ int v6m = v6j + v6k;
+ v6i = 8;
+ v6l++;
+ }
+ return v6i + v6j + v6k + v6l + v6n;
+}
+
+int
+f7 (void)
+{
+ int v7i = 6, v7j = 7, v7k = 9, v7l = 0, v7n = 0, v7o = 1;
+ #pragma omp parallel
+ {
+ #pragma omp master
+ v7o++;
+ #pragma omp for private (v7i) firstprivate (v7k) reduction (+:v7l)
+ for (v7n = 0; v7n < 3; v7n++)
+ {
+ int v7m = v7j + v7k;
+ v7i = 8;
+ v7l++;
+ }
+ }
+ return v7i + v7j + v7k + v7l + v7n;
+}
+
+int
+main (void)
+{
+ f1 ();
+ f2 ();
+ f3 ();
+ f4 ();
+ f5 ();
+ f6 ();
+ f7 ();
+ return 0;
+}