aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZdenek Dvorak <ook@ucw.cz>2007-08-01 13:50:39 +0200
committerZdenek Dvorak <rakdver@gcc.gnu.org>2007-08-01 11:50:39 +0000
commite5c95afe1e18581b060601f70b1a6888835028ce (patch)
treeff781d81e1c759d85b9e39299b57bf35bf7747a4
parent203bb67ec4596d07169474c03d36f7726e796120 (diff)
downloadgcc-e5c95afe1e18581b060601f70b1a6888835028ce.zip
gcc-e5c95afe1e18581b060601f70b1a6888835028ce.tar.gz
gcc-e5c95afe1e18581b060601f70b1a6888835028ce.tar.bz2
tree-pretty-print.c (dump_generic_node): Dump OMP_SECTIONS_SWITCH.
* tree-pretty-print.c (dump_generic_node): Dump OMP_SECTIONS_SWITCH. Display new operands of OMP_SECTIONS and OMP_CONTINUE. * tree.h (OMP_SECTIONS_CONTROL): New macro. (OMP_DIRECTIVE_P): Add OMP_SECTIONS_SWITCH. * omp-low.c (get_ws_args_for, determine_parallel_type, expand_omp_for_generic, expand_omp_for_static_nochunk, expand_omp_for_static_chunk, expand_omp_for, expand_omp_sections): Work with more precise CFG. (build_omp_regions_1): Handle OMP_SECTIONS_SWITCH. (lower_omp_sections): Emit OMP_SECTIONS_SWITCH. Add arguments to OMP_CONTINUE. * tree-gimple.c (is_gimple_stmt): Handle OMP_SECTIONS_SWITCH. * gimple-low.c (lower_stmt): Ditto. * tree-inline.c (estimate_num_insns_1): Ditto. * tree.def (OMP_SECTIONS, OMP_CONTINUE): Added new operands. (OMP_SECTIONS_SWITCH): New. * tree-cfgcleanup.c (cleanup_omp_return): New. (cleanup_tree_cfg_bb): Call cleanup_omp_return. * tree-cfg.c (make_edges): Create back edges for OMP_CONTINUE and exit edge for OMP_FOR. Handle OMP_SECTIONS_SWITCH. (tree_redirect_edge_and_branch): Handle omp constructs. * fortran/trans-openmp.c (gfc_trans_omp_sections): Build OMP_SECTIONS with three arguments. From-SVN: r127121
-rw-r--r--gcc/ChangeLog27
-rw-r--r--gcc/fortran/trans-openmp.c2
-rw-r--r--gcc/gimple-low.c1
-rw-r--r--gcc/omp-low.c302
-rw-r--r--gcc/tree-cfg.c38
-rw-r--r--gcc/tree-cfgcleanup.c35
-rw-r--r--gcc/tree-gimple.c1
-rw-r--r--gcc/tree-inline.c1
-rw-r--r--gcc/tree-pretty-print.c18
-rw-r--r--gcc/tree.def15
-rw-r--r--gcc/tree.h2
11 files changed, 277 insertions, 165 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6736648..d7afe17 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,32 @@
2007-08-01 Zdenek Dvorak <ook@ucw.cz>
+ * tree-pretty-print.c (dump_generic_node): Dump OMP_SECTIONS_SWITCH.
+ Display new operands of OMP_SECTIONS and OMP_CONTINUE.
+ * tree.h (OMP_SECTIONS_CONTROL): New macro.
+ (OMP_DIRECTIVE_P): Add OMP_SECTIONS_SWITCH.
+ * omp-low.c (get_ws_args_for, determine_parallel_type,
+ expand_omp_for_generic, expand_omp_for_static_nochunk,
+ expand_omp_for_static_chunk, expand_omp_for, expand_omp_sections):
+ Work with more precise CFG.
+ (build_omp_regions_1): Handle OMP_SECTIONS_SWITCH.
+ (lower_omp_sections): Emit OMP_SECTIONS_SWITCH. Add arguments to
+ OMP_CONTINUE.
+ * tree-gimple.c (is_gimple_stmt): Handle OMP_SECTIONS_SWITCH.
+ * gimple-low.c (lower_stmt): Ditto.
+ * tree-inline.c (estimate_num_insns_1): Ditto.
+ * tree.def (OMP_SECTIONS, OMP_CONTINUE): Added new operands.
+ (OMP_SECTIONS_SWITCH): New.
+ * tree-cfgcleanup.c (cleanup_omp_return): New.
+ (cleanup_tree_cfg_bb): Call cleanup_omp_return.
+ * tree-cfg.c (make_edges): Create back edges for OMP_CONTINUE
+ and exit edge for OMP_FOR. Handle OMP_SECTIONS_SWITCH.
+ (tree_redirect_edge_and_branch): Handle omp constructs.
+
+ * fortran/trans-openmp.c (gfc_trans_omp_sections): Build OMP_SECTIONS
+ with three arguments.
+
+2007-08-01 Zdenek Dvorak <ook@ucw.cz>
+
* tree-cfg.c (tree_merge_blocks): Preserve loop exit phi nodes only
in loop closed ssa.
diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c
index b068330..99fd1d0 100644
--- a/gcc/fortran/trans-openmp.c
+++ b/gcc/fortran/trans-openmp.c
@@ -1205,7 +1205,7 @@ gfc_trans_omp_sections (gfc_code *code, gfc_omp_clauses *clauses)
}
stmt = gfc_finish_block (&body);
- stmt = build2_v (OMP_SECTIONS, stmt, omp_clauses);
+ stmt = build3_v (OMP_SECTIONS, stmt, omp_clauses, NULL_TREE);
gfc_add_expr_to_block (&block, stmt);
return gfc_finish_block (&block);
diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c
index 8cab8bd..93532b9 100644
--- a/gcc/gimple-low.c
+++ b/gcc/gimple-low.c
@@ -244,6 +244,7 @@ lower_stmt (tree_stmt_iterator *tsi, struct lower_data *data)
case CHANGE_DYNAMIC_TYPE_EXPR:
case OMP_FOR:
case OMP_SECTIONS:
+ case OMP_SECTIONS_SWITCH:
case OMP_SECTION:
case OMP_SINGLE:
case OMP_MASTER:
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index feced73..bc1c821 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -347,8 +347,11 @@ get_ws_args_for (tree ws_stmt)
}
else if (TREE_CODE (ws_stmt) == OMP_SECTIONS)
{
- basic_block bb = bb_for_stmt (ws_stmt);
- t = build_int_cst (unsigned_type_node, EDGE_COUNT (bb->succs));
+ /* Number of sections is equal to the number of edges from the
+ OMP_SECTIONS_SWITCH statement, except for the one to the exit
+ of the sections region. */
+ basic_block bb = single_succ (bb_for_stmt (ws_stmt));
+ t = build_int_cst (unsigned_type_node, EDGE_COUNT (bb->succs) - 1);
t = tree_cons (NULL, t, NULL);
return t;
}
@@ -366,7 +369,8 @@ determine_parallel_type (struct omp_region *region)
basic_block ws_entry_bb, ws_exit_bb;
if (region == NULL || region->inner == NULL
- || region->exit == NULL || region->inner->exit == NULL)
+ || region->exit == NULL || region->inner->exit == NULL
+ || region->inner->cont == NULL)
return;
/* We only support parallel+for and parallel+sections. */
@@ -2566,7 +2570,7 @@ expand_omp_parallel (struct omp_region *region)
L3:
If this is a combined omp parallel loop, instead of the call to
- GOMP_loop_foo_start, we emit 'goto L3'. */
+ GOMP_loop_foo_start, we emit 'goto L2'. */
static void
expand_omp_for_generic (struct omp_region *region,
@@ -2580,6 +2584,9 @@ expand_omp_for_generic (struct omp_region *region,
basic_block l2_bb = NULL, l3_bb = NULL;
block_stmt_iterator si;
bool in_combined_parallel = is_combined_parallel (region);
+ bool broken_loop = region->cont == NULL;
+
+ gcc_assert (!broken_loop || !in_combined_parallel);
type = TREE_TYPE (fd->v);
@@ -2589,19 +2596,23 @@ expand_omp_for_generic (struct omp_region *region,
TREE_ADDRESSABLE (istart0) = 1;
TREE_ADDRESSABLE (iend0) = 1;
- gcc_assert ((region->cont != NULL) ^ (region->exit == NULL));
-
entry_bb = region->entry;
- l0_bb = create_empty_bb (entry_bb);
- l1_bb = single_succ (entry_bb);
-
cont_bb = region->cont;
- exit_bb = region->exit;
- if (cont_bb)
+ gcc_assert (EDGE_COUNT (entry_bb->succs) == 2);
+ gcc_assert (broken_loop
+ || BRANCH_EDGE (entry_bb)->dest == FALLTHRU_EDGE (cont_bb)->dest);
+ l0_bb = split_edge (FALLTHRU_EDGE (entry_bb));
+ l1_bb = single_succ (l0_bb);
+ if (!broken_loop)
{
l2_bb = create_empty_bb (cont_bb);
- l3_bb = single_succ (cont_bb);
+ gcc_assert (BRANCH_EDGE (cont_bb)->dest == l1_bb);
+ gcc_assert (EDGE_COUNT (cont_bb->succs) == 2);
}
+ else
+ l2_bb = NULL;
+ l3_bb = BRANCH_EDGE (entry_bb)->dest;
+ exit_bb = region->exit;
si = bsi_last (entry_bb);
gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_FOR);
@@ -2626,11 +2637,8 @@ expand_omp_for_generic (struct omp_region *region,
t = build_call_expr (built_in_decls[start_fn], 5,
t0, t1, t2, t3, t4);
t = get_formal_tmp_var (t, &list);
- if (cont_bb)
- {
- t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
- append_to_statement_list (t, &list);
- }
+ t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
+ append_to_statement_list (t, &list);
bsi_insert_after (&si, list, BSI_SAME_STMT);
}
bsi_remove (&si, true);
@@ -2648,47 +2656,39 @@ expand_omp_for_generic (struct omp_region *region,
si = bsi_start (l0_bb);
bsi_insert_after (&si, list, BSI_CONTINUE_LINKING);
- /* Handle the rare case where BODY doesn't ever return. */
- if (cont_bb == NULL)
+ if (!broken_loop)
{
- remove_edge (single_succ_edge (entry_bb));
- make_edge (entry_bb, l0_bb, EDGE_FALLTHRU);
- make_edge (l0_bb, l1_bb, EDGE_FALLTHRU);
- return;
- }
-
- /* Code to control the increment and predicate for the sequential
- loop goes in the first half of EXIT_BB (we split EXIT_BB so
- that we can inherit all the edges going out of the loop
- body). */
- list = alloc_stmt_list ();
+ /* Code to control the increment and predicate for the sequential
+ loop goes in the CONT_BB. */
+ list = alloc_stmt_list ();
- t = build2 (PLUS_EXPR, type, fd->v, fd->step);
- t = build_gimple_modify_stmt (fd->v, t);
- gimplify_and_add (t, &list);
+ t = build2 (PLUS_EXPR, type, fd->v, fd->step);
+ t = build_gimple_modify_stmt (fd->v, t);
+ gimplify_and_add (t, &list);
- t = build2 (fd->cond_code, boolean_type_node, fd->v, iend);
- t = get_formal_tmp_var (t, &list);
- t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
- append_to_statement_list (t, &list);
+ t = build2 (fd->cond_code, boolean_type_node, fd->v, iend);
+ t = get_formal_tmp_var (t, &list);
+ t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
+ append_to_statement_list (t, &list);
- si = bsi_last (cont_bb);
- bsi_insert_after (&si, list, BSI_SAME_STMT);
- gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_CONTINUE);
- bsi_remove (&si, true);
+ si = bsi_last (cont_bb);
+ bsi_insert_after (&si, list, BSI_SAME_STMT);
+ gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_CONTINUE);
+ bsi_remove (&si, true);
- /* Emit code to get the next parallel iteration in L2_BB. */
- list = alloc_stmt_list ();
+ /* Emit code to get the next parallel iteration in L2_BB. */
+ list = alloc_stmt_list ();
- t = build_call_expr (built_in_decls[next_fn], 2,
- build_fold_addr_expr (istart0),
- build_fold_addr_expr (iend0));
- t = get_formal_tmp_var (t, &list);
- t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
- append_to_statement_list (t, &list);
+ t = build_call_expr (built_in_decls[next_fn], 2,
+ build_fold_addr_expr (istart0),
+ build_fold_addr_expr (iend0));
+ t = get_formal_tmp_var (t, &list);
+ t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
+ append_to_statement_list (t, &list);
- si = bsi_start (l2_bb);
- bsi_insert_after (&si, list, BSI_CONTINUE_LINKING);
+ si = bsi_start (l2_bb);
+ bsi_insert_after (&si, list, BSI_CONTINUE_LINKING);
+ }
/* Add the loop cleanup function. */
si = bsi_last (exit_bb);
@@ -2701,23 +2701,26 @@ expand_omp_for_generic (struct omp_region *region,
bsi_remove (&si, true);
/* Connect the new blocks. */
- remove_edge (single_succ_edge (entry_bb));
if (in_combined_parallel)
- make_edge (entry_bb, l2_bb, EDGE_FALLTHRU);
+ {
+ remove_edge (BRANCH_EDGE (entry_bb));
+ redirect_edge_and_branch (single_succ_edge (entry_bb), l2_bb);
+ }
else
{
- make_edge (entry_bb, l0_bb, EDGE_TRUE_VALUE);
- make_edge (entry_bb, l3_bb, EDGE_FALSE_VALUE);
+ find_edge (entry_bb, l0_bb)->flags = EDGE_TRUE_VALUE;
+ find_edge (entry_bb, l3_bb)->flags = EDGE_FALSE_VALUE;
}
- make_edge (l0_bb, l1_bb, EDGE_FALLTHRU);
-
- remove_edge (single_succ_edge (cont_bb));
- make_edge (cont_bb, l1_bb, EDGE_TRUE_VALUE);
- make_edge (cont_bb, l2_bb, EDGE_FALSE_VALUE);
+ if (!broken_loop)
+ {
+ find_edge (cont_bb, l1_bb)->flags = EDGE_TRUE_VALUE;
+ remove_edge (find_edge (cont_bb, l3_bb));
+ make_edge (cont_bb, l2_bb, EDGE_FALSE_VALUE);
- make_edge (l2_bb, l0_bb, EDGE_TRUE_VALUE);
- make_edge (l2_bb, l3_bb, EDGE_FALSE_VALUE);
+ make_edge (l2_bb, l0_bb, EDGE_TRUE_VALUE);
+ make_edge (l2_bb, l3_bb, EDGE_FALSE_VALUE);
+ }
}
@@ -2762,10 +2765,14 @@ expand_omp_for_static_nochunk (struct omp_region *region,
type = TREE_TYPE (fd->v);
entry_bb = region->entry;
- seq_start_bb = create_empty_bb (entry_bb);
- body_bb = single_succ (entry_bb);
cont_bb = region->cont;
- fin_bb = single_succ (cont_bb);
+ gcc_assert (EDGE_COUNT (entry_bb->succs) == 2);
+ gcc_assert (BRANCH_EDGE (entry_bb)->dest == FALLTHRU_EDGE (cont_bb)->dest);
+ seq_start_bb = split_edge (FALLTHRU_EDGE (entry_bb));
+ body_bb = single_succ (seq_start_bb);
+ gcc_assert (BRANCH_EDGE (cont_bb)->dest == body_bb);
+ gcc_assert (EDGE_COUNT (cont_bb->succs) == 2);
+ fin_bb = FALLTHRU_EDGE (cont_bb)->dest;
exit_bb = region->exit;
/* Iteration space partitioning goes in ENTRY_BB. */
@@ -2871,13 +2878,10 @@ expand_omp_for_static_nochunk (struct omp_region *region,
bsi_remove (&si, true);
/* Connect all the blocks. */
- make_edge (seq_start_bb, body_bb, EDGE_FALLTHRU);
-
- remove_edge (single_succ_edge (entry_bb));
- make_edge (entry_bb, fin_bb, EDGE_TRUE_VALUE);
- make_edge (entry_bb, seq_start_bb, EDGE_FALSE_VALUE);
-
- make_edge (cont_bb, body_bb, EDGE_TRUE_VALUE);
+ find_edge (entry_bb, seq_start_bb)->flags = EDGE_FALSE_VALUE;
+ find_edge (entry_bb, fin_bb)->flags = EDGE_TRUE_VALUE;
+
+ find_edge (cont_bb, body_bb)->flags = EDGE_TRUE_VALUE;
find_edge (cont_bb, fin_bb)->flags = EDGE_FALSE_VALUE;
}
@@ -2923,16 +2927,24 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
basic_block trip_update_bb, cont_bb, fin_bb;
tree list;
block_stmt_iterator si;
+ edge se;
type = TREE_TYPE (fd->v);
entry_bb = region->entry;
- iter_part_bb = create_empty_bb (entry_bb);
- seq_start_bb = create_empty_bb (iter_part_bb);
- body_bb = single_succ (entry_bb);
+ se = split_block (entry_bb, last_stmt (entry_bb));
+ entry_bb = se->src;
+ iter_part_bb = se->dest;
cont_bb = region->cont;
- trip_update_bb = create_empty_bb (cont_bb);
- fin_bb = single_succ (cont_bb);
+ gcc_assert (EDGE_COUNT (iter_part_bb->succs) == 2);
+ gcc_assert (BRANCH_EDGE (iter_part_bb)->dest
+ == FALLTHRU_EDGE (cont_bb)->dest);
+ seq_start_bb = split_edge (FALLTHRU_EDGE (iter_part_bb));
+ body_bb = single_succ (seq_start_bb);
+ gcc_assert (BRANCH_EDGE (cont_bb)->dest == body_bb);
+ gcc_assert (EDGE_COUNT (cont_bb->succs) == 2);
+ fin_bb = FALLTHRU_EDGE (cont_bb)->dest;
+ trip_update_bb = split_edge (FALLTHRU_EDGE (cont_bb));
exit_bb = region->exit;
/* Trip and adjustment setup goes in ENTRY_BB. */
@@ -3057,19 +3069,13 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
bsi_remove (&si, true);
/* Connect the new blocks. */
- remove_edge (single_succ_edge (entry_bb));
- make_edge (entry_bb, iter_part_bb, EDGE_FALLTHRU);
-
- make_edge (iter_part_bb, seq_start_bb, EDGE_TRUE_VALUE);
- make_edge (iter_part_bb, fin_bb, EDGE_FALSE_VALUE);
-
- make_edge (seq_start_bb, body_bb, EDGE_FALLTHRU);
-
- remove_edge (single_succ_edge (cont_bb));
- make_edge (cont_bb, body_bb, EDGE_TRUE_VALUE);
- make_edge (cont_bb, trip_update_bb, EDGE_FALSE_VALUE);
-
- make_edge (trip_update_bb, iter_part_bb, EDGE_FALLTHRU);
+ find_edge (iter_part_bb, seq_start_bb)->flags = EDGE_TRUE_VALUE;
+ find_edge (iter_part_bb, fin_bb)->flags = EDGE_FALSE_VALUE;
+
+ find_edge (cont_bb, body_bb)->flags = EDGE_TRUE_VALUE;
+ find_edge (cont_bb, trip_update_bb)->flags = EDGE_FALSE_VALUE;
+
+ redirect_edge_and_branch (single_succ_edge (trip_update_bb), iter_part_bb);
}
@@ -3087,8 +3093,7 @@ expand_omp_for (struct omp_region *region)
if (fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC
&& !fd.have_ordered
- && region->cont
- && region->exit)
+ && region->cont != NULL)
{
if (fd.chunk_size == NULL)
expand_omp_for_static_nochunk (region, &fd);
@@ -3137,55 +3142,50 @@ expand_omp_for (struct omp_region *region)
static void
expand_omp_sections (struct omp_region *region)
{
- tree label_vec, l0, l1, l2, t, u, v, sections_stmt;
- unsigned i, len;
- basic_block entry_bb, exit_bb, l0_bb, l1_bb, l2_bb, default_bb;
+ tree label_vec, l1, l2, t, u, v, sections_stmt;
+ unsigned i, casei, len;
+ basic_block entry_bb, l0_bb, l1_bb, l2_bb, default_bb;
block_stmt_iterator si;
struct omp_region *inner;
- edge e;
+ bool exit_reachable = region->cont != NULL;
+ gcc_assert (exit_reachable == (region->exit != NULL));
entry_bb = region->entry;
- l0_bb = create_empty_bb (entry_bb);
- l0 = tree_block_label (l0_bb);
-
- gcc_assert ((region->cont != NULL) ^ (region->exit == NULL));
+ l0_bb = single_succ (entry_bb);
l1_bb = region->cont;
- if (l1_bb)
+ l2_bb = region->exit;
+ if (exit_reachable)
{
- l2_bb = single_succ (l1_bb);
+ gcc_assert (single_pred (l2_bb) == l0_bb);
default_bb = create_empty_bb (l1_bb->prev_bb);
-
l1 = tree_block_label (l1_bb);
+ l2 = tree_block_label (l2_bb);
}
else
{
- l2_bb = create_empty_bb (l0_bb);
- default_bb = l2_bb;
-
- l1 = NULL;
+ default_bb = create_empty_bb (l0_bb);
+ l1 = NULL_TREE;
+ l2 = tree_block_label (default_bb);
}
- l2 = tree_block_label (l2_bb);
-
- exit_bb = region->exit;
-
- v = create_tmp_var (unsigned_type_node, ".section");
/* We will build a switch() with enough cases for all the
OMP_SECTION regions, a '0' case to handle the end of more work
and a default case to abort if something goes wrong. */
- len = EDGE_COUNT (entry_bb->succs);
- label_vec = make_tree_vec (len + 2);
+ len = EDGE_COUNT (l0_bb->succs);
+ label_vec = make_tree_vec (len + 1);
/* The call to GOMP_sections_start goes in ENTRY_BB, replacing the
OMP_SECTIONS statement. */
si = bsi_last (entry_bb);
sections_stmt = bsi_stmt (si);
gcc_assert (TREE_CODE (sections_stmt) == OMP_SECTIONS);
+ v = OMP_SECTIONS_CONTROL (sections_stmt);
if (!is_combined_parallel (region))
{
/* If we are not inside a combined parallel+sections region,
call GOMP_sections_start. */
- t = build_int_cst (unsigned_type_node, len);
+ t = build_int_cst (unsigned_type_node,
+ exit_reachable ? len - 1 : len);
u = built_in_decls[BUILT_IN_GOMP_SECTIONS_START];
t = build_call_expr (u, 1, t);
t = build_gimple_modify_stmt (v, t);
@@ -3193,19 +3193,27 @@ expand_omp_sections (struct omp_region *region)
}
bsi_remove (&si, true);
- /* The switch() statement replacing OMP_SECTIONS goes in L0_BB. */
- si = bsi_start (l0_bb);
+ /* The switch() statement replacing OMP_SECTIONS_SWITCH goes in L0_BB. */
+ si = bsi_last (l0_bb);
+ gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_SECTIONS_SWITCH);
t = build3 (SWITCH_EXPR, void_type_node, v, NULL, label_vec);
- bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
+ bsi_insert_after (&si, t, BSI_SAME_STMT);
+ bsi_remove (&si, true);
- t = build3 (CASE_LABEL_EXPR, void_type_node,
- build_int_cst (unsigned_type_node, 0), NULL, l2);
- TREE_VEC_ELT (label_vec, 0) = t;
- make_edge (l0_bb, l2_bb, 0);
+ i = 0;
+ if (exit_reachable)
+ {
+ t = build3 (CASE_LABEL_EXPR, void_type_node,
+ build_int_cst (unsigned_type_node, 0), NULL, l2);
+ TREE_VEC_ELT (label_vec, 0) = t;
+ i++;
+ }
/* Convert each OMP_SECTION into a CASE_LABEL_EXPR. */
- for (inner = region->inner, i = 1; inner; inner = inner->next, ++i)
+ for (inner = region->inner, casei = 1;
+ inner;
+ inner = inner->next, i++, casei++)
{
basic_block s_entry_bb, s_exit_bb;
@@ -3213,7 +3221,7 @@ expand_omp_sections (struct omp_region *region)
s_exit_bb = inner->exit;
t = tree_block_label (s_entry_bb);
- u = build_int_cst (unsigned_type_node, i);
+ u = build_int_cst (unsigned_type_node, casei);
u = build3 (CASE_LABEL_EXPR, void_type_node, u, NULL, t);
TREE_VEC_ELT (label_vec, i) = u;
@@ -3221,11 +3229,6 @@ expand_omp_sections (struct omp_region *region)
gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_SECTION);
gcc_assert (i < len || OMP_SECTION_LAST (bsi_stmt (si)));
bsi_remove (&si, true);
-
- e = single_pred_edge (s_entry_bb);
- e->flags = 0;
- redirect_edge_pred (e, l0_bb);
-
single_succ_edge (s_entry_bb)->flags = EDGE_FALLTHRU;
if (s_exit_bb == NULL)
@@ -3241,16 +3244,16 @@ expand_omp_sections (struct omp_region *region)
/* Error handling code goes in DEFAULT_BB. */
t = tree_block_label (default_bb);
u = build3 (CASE_LABEL_EXPR, void_type_node, NULL, NULL, t);
- TREE_VEC_ELT (label_vec, len + 1) = u;
+ TREE_VEC_ELT (label_vec, len) = u;
make_edge (l0_bb, default_bb, 0);
si = bsi_start (default_bb);
t = build_call_expr (built_in_decls[BUILT_IN_TRAP], 0);
bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
- /* Code to get the next section goes in L1_BB. */
- if (l1_bb)
+ if (exit_reachable)
{
+ /* Code to get the next section goes in L1_BB. */
si = bsi_last (l1_bb);
gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_CONTINUE);
@@ -3258,12 +3261,11 @@ expand_omp_sections (struct omp_region *region)
t = build_gimple_modify_stmt (v, t);
bsi_insert_after (&si, t, BSI_SAME_STMT);
bsi_remove (&si, true);
- }
- /* Cleanup function replaces OMP_RETURN in EXIT_BB. */
- if (exit_bb)
- {
- si = bsi_last (exit_bb);
+ single_succ_edge (l1_bb)->flags = EDGE_FALLTHRU;
+
+ /* Cleanup function replaces OMP_RETURN in EXIT_BB. */
+ si = bsi_last (l2_bb);
if (OMP_RETURN_NOWAIT (bsi_stmt (si)))
t = built_in_decls[BUILT_IN_GOMP_SECTIONS_END_NOWAIT];
else
@@ -3279,16 +3281,8 @@ expand_omp_sections (struct omp_region *region)
/* If this was a combined parallel+sections region, we did not
emit a GOMP_sections_start in the entry block, so we just
need to jump to L1_BB to get the next section. */
- make_edge (entry_bb, l1_bb, EDGE_FALLTHRU);
- }
- else
- make_edge (entry_bb, l0_bb, EDGE_FALLTHRU);
-
- if (l1_bb)
- {
- e = single_succ_edge (l1_bb);
- redirect_edge_succ (e, l0_bb);
- e->flags = EDGE_FALLTHRU;
+ gcc_assert (exit_reachable);
+ redirect_edge_and_branch (single_succ_edge (entry_bb), l1_bb);
}
}
@@ -3451,6 +3445,11 @@ build_omp_regions_1 (basic_block bb, struct omp_region *parent)
gcc_assert (parent);
parent->cont = bb;
}
+ else if (code == OMP_SECTIONS_SWITCH)
+ {
+ /* OMP_SECTIONS_SWITCH is part of OMP_SECTIONS, and we do nothing for
+ it. */
+ }
else
{
/* Otherwise, this directive becomes the parent for a new
@@ -3539,7 +3538,7 @@ struct tree_opt_pass pass_expand_omp =
static void
lower_omp_sections (tree *stmt_p, omp_context *ctx)
{
- tree new_stmt, stmt, body, bind, block, ilist, olist, new_body;
+ tree new_stmt, stmt, body, bind, block, ilist, olist, new_body, control;
tree t, dlist;
tree_stmt_iterator tsi;
unsigned i, len;
@@ -3601,9 +3600,12 @@ 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);
+ append_to_statement_list (make_node (OMP_SECTIONS_SWITCH), &new_body);
append_to_statement_list (bind, &new_body);
- t = make_node (OMP_CONTINUE);
+ control = create_tmp_var (unsigned_type_node, ".section");
+ t = build2 (OMP_CONTINUE, void_type_node, control, control);
+ OMP_SECTIONS_CONTROL (stmt) = control;
append_to_statement_list (t, &new_body);
append_to_statement_list (olist, &new_body);
@@ -4040,7 +4042,7 @@ lower_omp_for (tree *stmt_p, omp_context *ctx)
append_to_statement_list (OMP_FOR_BODY (stmt), body_p);
- t = make_node (OMP_CONTINUE);
+ t = build2 (OMP_CONTINUE, void_type_node, fd.v, fd.v);
append_to_statement_list (t, body_p);
/* After the loop, add exit clauses. */
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index c24b1c6..f124c9a 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -517,6 +517,10 @@ make_edges (void)
case OMP_SECTIONS:
cur_region = new_omp_region (bb, code, cur_region);
+ fallthru = true;
+ break;
+
+ case OMP_SECTIONS_SWITCH:
fallthru = false;
break;
@@ -533,31 +537,42 @@ make_edges (void)
switch (cur_region->type)
{
case OMP_FOR:
- /* ??? Technically there should be a some sort of loopback
- edge here, but it goes to a block that doesn't exist yet,
- and without it, updating the ssa form would be a real
- bear. Fortunately, we don't yet do ssa before expanding
- these nodes. */
+ /* Make the loopback edge. */
+ make_edge (bb, single_succ (cur_region->entry), 0);
+
+ /* Create an edge from OMP_FOR to exit, which corresponds to
+ the case that the body of the loop is not executed at
+ all. */
+ make_edge (cur_region->entry, bb->next_bb, 0);
+ fallthru = true;
break;
case OMP_SECTIONS:
/* Wire up the edges into and out of the nested sections. */
- /* ??? Similarly wrt loopback. */
{
+ basic_block switch_bb = single_succ (cur_region->entry);
+
struct omp_region *i;
for (i = cur_region->inner; i ; i = i->next)
{
gcc_assert (i->type == OMP_SECTION);
- make_edge (cur_region->entry, i->entry, 0);
+ make_edge (switch_bb, i->entry, 0);
make_edge (i->exit, bb, EDGE_FALLTHRU);
}
+
+ /* Make the loopback edge to the block with
+ OMP_SECTIONS_SWITCH. */
+ make_edge (bb, switch_bb, 0);
+
+ /* Make the edge from the switch to exit. */
+ make_edge (switch_bb, bb->next_bb, 0);
+ fallthru = false;
}
break;
default:
gcc_unreachable ();
}
- fallthru = true;
break;
default:
@@ -4807,6 +4822,13 @@ tree_redirect_edge_and_branch (edge e, basic_block dest)
e->flags |= EDGE_FALLTHRU;
break;
+ case OMP_RETURN:
+ case OMP_CONTINUE:
+ case OMP_SECTIONS_SWITCH:
+ case OMP_FOR:
+ /* The edges from OMP constructs can be simply redirected. */
+ break;
+
default:
/* Otherwise it must be a fallthru edge, and we don't need to
do anything besides redirecting it. */
diff --git a/gcc/tree-cfgcleanup.c b/gcc/tree-cfgcleanup.c
index c35001c..bd2523b 100644
--- a/gcc/tree-cfgcleanup.c
+++ b/gcc/tree-cfgcleanup.c
@@ -507,6 +507,36 @@ split_bbs_on_noreturn_calls (void)
return changed;
}
+/* If OMP_RETURN in basic block BB is unreachable, remove it. */
+
+static bool
+cleanup_omp_return (basic_block bb)
+{
+ tree stmt = last_stmt (bb);
+ basic_block control_bb;
+
+ if (stmt == NULL_TREE
+ || TREE_CODE (stmt) != OMP_RETURN
+ || !single_pred_p (bb))
+ return false;
+
+ control_bb = single_pred (bb);
+ stmt = last_stmt (control_bb);
+
+ if (TREE_CODE (stmt) != OMP_SECTIONS_SWITCH)
+ return false;
+
+ /* The block with the control statement normally has two entry edges -- one
+ from entry, one from continue. If continue is removed, return is
+ unreachable, so we remove it here as well. */
+ if (EDGE_COUNT (control_bb->preds) == 2)
+ return false;
+
+ gcc_assert (EDGE_COUNT (control_bb->preds) == 1);
+ remove_edge_and_dominated_blocks (single_pred_edge (bb));
+ return true;
+}
+
/* Tries to cleanup cfg in basic block BB. Returns true if anything
changes. */
@@ -515,8 +545,11 @@ cleanup_tree_cfg_bb (basic_block bb)
{
bool retval = false;
- retval = cleanup_control_flow_bb (bb);
+ if (cleanup_omp_return (bb))
+ return true;
+ retval = cleanup_control_flow_bb (bb);
+
/* Forwarder blocks can carry line number information which is
useful when debugging, so we only clean them up when
optimizing. */
diff --git a/gcc/tree-gimple.c b/gcc/tree-gimple.c
index 181b16f..e9753eb 100644
--- a/gcc/tree-gimple.c
+++ b/gcc/tree-gimple.c
@@ -230,6 +230,7 @@ is_gimple_stmt (tree t)
case OMP_PARALLEL:
case OMP_FOR:
case OMP_SECTIONS:
+ case OMP_SECTIONS_SWITCH:
case OMP_SECTION:
case OMP_SINGLE:
case OMP_MASTER:
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 33b369d..af0c7d4 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -2010,6 +2010,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
case OMP_CLAUSE:
case OMP_RETURN:
case OMP_CONTINUE:
+ case OMP_SECTIONS_SWITCH:
break;
/* We don't account constants for now. Assume that the cost is amortized
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index 77ecb953..bd71a7d 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -1851,9 +1851,21 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
case OMP_SECTIONS:
pp_string (buffer, "#pragma omp sections");
+ if (OMP_SECTIONS_CONTROL (node))
+ {
+ pp_string (buffer, " <");
+ dump_generic_node (buffer, OMP_SECTIONS_CONTROL (node), spc,
+ flags, false);
+ pp_string (buffer, ">");
+ }
dump_omp_clauses (buffer, OMP_SECTIONS_CLAUSES (node), spc, flags);
goto dump_omp_body;
+ case OMP_SECTIONS_SWITCH:
+ pp_string (buffer, "OMP_SECTIONS_SWITCH");
+ is_expr = false;
+ break;
+
case OMP_SECTION:
pp_string (buffer, "#pragma omp section");
goto dump_omp_body;
@@ -1901,7 +1913,11 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
break;
case OMP_CONTINUE:
- pp_string (buffer, "OMP_CONTINUE");
+ pp_string (buffer, "OMP_CONTINUE <");
+ dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
+ pp_string (buffer, " <- ");
+ dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false);
+ pp_string (buffer, ">");
is_expr = false;
break;
diff --git a/gcc/tree.def b/gcc/tree.def
index aa95cb1..72c6d24 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -999,8 +999,14 @@ DEFTREECODE (OMP_FOR, "omp_for", tcc_statement, 6)
/* OpenMP - #pragma omp sections [clause1 ... clauseN]
Operand 0: OMP_SECTIONS_BODY: Sections body.
- Operand 1: OMP_SECTIONS_CLAUSES: List of clauses. */
-DEFTREECODE (OMP_SECTIONS, "omp_sections", tcc_statement, 2)
+ Operand 1: OMP_SECTIONS_CLAUSES: List of clauses.
+ Operand 2: OMP_SECTIONS_CONTROL: The control variable used for deciding
+ which of the sections to execute. */
+DEFTREECODE (OMP_SECTIONS, "omp_sections", tcc_statement, 3)
+
+/* This tree immediatelly follows OMP_SECTIONS, and represents the switch
+ used to decide which branch is taken. */
+DEFTREECODE (OMP_SECTIONS_SWITCH, "omp_sections_switch", tcc_statement, 0)
/* OpenMP - #pragma omp single
Operand 0: OMP_SINGLE_BODY: Single section body.
@@ -1028,8 +1034,9 @@ DEFTREECODE (OMP_CRITICAL, "omp_critical", tcc_statement, 2)
DEFTREECODE (OMP_RETURN, "omp_return", tcc_statement, 0)
/* OpenMP - An intermediate tree code to mark the location of the
- loop or sections iteration in the partially lowered code. */
-DEFTREECODE (OMP_CONTINUE, "omp_continue", tcc_statement, 0)
+ loop or sections iteration in the partially lowered code.
+ The arguments are definition and use of the control variable. */
+DEFTREECODE (OMP_CONTINUE, "omp_continue", tcc_statement, 2)
/* OpenMP - #pragma omp atomic
Operand 0: The address at which the atomic operation is to be performed.
diff --git a/gcc/tree.h b/gcc/tree.h
index 9468982..f955b87 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -187,6 +187,7 @@ extern const enum tree_code_class tree_code_type[];
(TREE_CODE (NODE) == OMP_PARALLEL \
|| TREE_CODE (NODE) == OMP_FOR \
|| TREE_CODE (NODE) == OMP_SECTIONS \
+ || TREE_CODE (NODE) == OMP_SECTIONS_SWITCH \
|| TREE_CODE (NODE) == OMP_SINGLE \
|| TREE_CODE (NODE) == OMP_SECTION \
|| TREE_CODE (NODE) == OMP_MASTER \
@@ -1695,6 +1696,7 @@ struct tree_constructor GTY(())
#define OMP_SECTIONS_BODY(NODE) TREE_OPERAND (OMP_SECTIONS_CHECK (NODE), 0)
#define OMP_SECTIONS_CLAUSES(NODE) TREE_OPERAND (OMP_SECTIONS_CHECK (NODE), 1)
+#define OMP_SECTIONS_CONTROL(NODE) TREE_OPERAND (OMP_SECTIONS_CHECK (NODE), 2)
#define OMP_SECTION_BODY(NODE) TREE_OPERAND (OMP_SECTION_CHECK (NODE), 0)