From ac6e3339fccf89d6b4b36cdb254390f05de9201b Mon Sep 17 00:00:00 2001 From: rakdver Date: Wed, 1 Aug 2007 11:50:39 +0000 Subject: [PATCH] * 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@127121 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 27 ++++ gcc/fortran/trans-openmp.c | 2 +- gcc/gimple-low.c | 1 + gcc/omp-low.c | 302 +++++++++++++++++++++++---------------------- gcc/tree-cfg.c | 38 ++++-- gcc/tree-cfgcleanup.c | 35 +++++- gcc/tree-gimple.c | 1 + gcc/tree-inline.c | 1 + gcc/tree-pretty-print.c | 18 ++- gcc/tree.def | 15 ++- gcc/tree.h | 2 + 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 + * 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 + * 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 77ecb95..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) -- 2.7.4