From 41b37d5ec1064decf497f1ce4657582f4b4807c8 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 19 May 2015 18:16:15 +0200 Subject: [PATCH] re PR middle-end/66199 (lastprivate/linear clause issues on combined constructs) PR middle-end/66199 * tree.h (OMP_TEAMS_COMBINED): Define. * gimplify.c (enum gimplify_omp_var_data): Add GOVD_LINEAR_LASTPRIVATE_NO_OUTER. (enum omp_region_type): Add ORT_COMBINED_TEAMS. (omp_notice_variable): Accept both ORT_TEAMS and ORT_COMBINED_TEAMS. Don't recurse if GOVD_LINEAR_LASTPRIVATE_NO_OUTER is set and either GOVD_LINEAR is set, or GOVD_LASTPRIVATE without GOVD_FIRSTPRIVATE. (omp_no_lastprivate): New function. (gimplify_scan_omp_clauses): For OMP_CLAUSE_LASTPRIVATE and OMP_CLAUSE_LINEAR, if omp_no_lastprivate, don't notice_outer and set appropriate bits, otherwise make sure default(none) combined constructs won't complain. (gimplify_adjust_omp_clauses): Remove OMP_CLAUSE_LINEAR outer special casing, for OMP_CLAUSE_LASTPRIVATE if omp_no_lastprivate either remove the clause or turn it into OMP_CLAUSE_PRIVATE. (gimplify_omp_for): Fix up handling of implicit lastprivate or linear iterators. (gimplify_omp_workshare): For OMP_TEAMS_COMBINED use ORT_COMBINED_TEAMS. * omp-low.c (lower_omp_for_lastprivate): For combined for simd use fd.loop.n2 from the for rather than simd. gcc/c/ * c-parser.c (c_parser_omp_for_loop): Don't add OMP_CLAUSE_SHARED to OMP_PARALLEL_CLAUSES when moving OMP_CLAUSE_LASTPRIVATE clause to OMP_FOR_CLAUSES. (c_parser_omp_teams): Set OMP_TEAMS_COMBINED for combined constructs. gcc/cp/ * parser.c (cp_parser_omp_for_loop): Don't add OMP_CLAUSE_SHARED to OMP_PARALLEL_CLAUSES when moving OMP_CLAUSE_LASTPRIVATE clause to OMP_FOR_CLAUSES. (cp_parser_omp_teams): Set OMP_TEAMS_COMBINED for combined constructs. gcc/fortran/ * trans-openmp.c (gfc_trans_omp_teams): Set OMP_TEAMS_COMBINED for combined constructs. (gfc_trans_omp_target): Make sure BIND_EXPR has non-NULL BIND_EXPR_BLOCK. libgomp/ * testsuite/libgomp.c/pr66199-1.c: New test. * testsuite/libgomp.c/pr66199-2.c: New test. * testsuite/libgomp.c++/pr66199-1.C: New test. * testsuite/libgomp.c++/pr66199-2.C: New test. * testsuite/libgomp.fortran/pr66199-1.f90: New test. * testsuite/libgomp.fortran/pr66199-2.f90: New test. From-SVN: r223387 --- gcc/ChangeLog | 28 ++ gcc/c/ChangeLog | 9 + gcc/c/c-parser.c | 11 +- gcc/cp/ChangeLog | 9 + gcc/cp/parser.c | 11 +- gcc/fortran/ChangeLog | 8 + gcc/fortran/trans-openmp.c | 15 +- gcc/gimplify.c | 262 ++++++++++++++---- gcc/omp-low.c | 16 +- gcc/tree.h | 5 + libgomp/ChangeLog | 10 + libgomp/testsuite/libgomp.c++/pr66199-1.C | 5 + libgomp/testsuite/libgomp.c++/pr66199-2.C | 5 + libgomp/testsuite/libgomp.c/pr66199-1.c | 62 +++++ libgomp/testsuite/libgomp.c/pr66199-2.c | 59 ++++ .../testsuite/libgomp.fortran/pr66199-1.f90 | 49 ++++ .../testsuite/libgomp.fortran/pr66199-2.f90 | 47 ++++ 17 files changed, 540 insertions(+), 71 deletions(-) create mode 100644 libgomp/testsuite/libgomp.c++/pr66199-1.C create mode 100644 libgomp/testsuite/libgomp.c++/pr66199-2.C create mode 100644 libgomp/testsuite/libgomp.c/pr66199-1.c create mode 100644 libgomp/testsuite/libgomp.c/pr66199-2.c create mode 100644 libgomp/testsuite/libgomp.fortran/pr66199-1.f90 create mode 100644 libgomp/testsuite/libgomp.fortran/pr66199-2.f90 diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 778019dc50b..5ab8283a8be 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,31 @@ +2015-05-19 Jakub Jelinek + + PR middle-end/66199 + * tree.h (OMP_TEAMS_COMBINED): Define. + * gimplify.c (enum gimplify_omp_var_data): Add + GOVD_LINEAR_LASTPRIVATE_NO_OUTER. + (enum omp_region_type): Add ORT_COMBINED_TEAMS. + (omp_notice_variable): Accept both ORT_TEAMS + and ORT_COMBINED_TEAMS. Don't recurse if + GOVD_LINEAR_LASTPRIVATE_NO_OUTER is set and either + GOVD_LINEAR is set, or GOVD_LASTPRIVATE without + GOVD_FIRSTPRIVATE. + (omp_no_lastprivate): New function. + (gimplify_scan_omp_clauses): For OMP_CLAUSE_LASTPRIVATE + and OMP_CLAUSE_LINEAR, if omp_no_lastprivate, don't + notice_outer and set appropriate bits, otherwise make + sure default(none) combined constructs won't complain. + (gimplify_adjust_omp_clauses): Remove OMP_CLAUSE_LINEAR + outer special casing, for OMP_CLAUSE_LASTPRIVATE if + omp_no_lastprivate either remove the clause or turn it + into OMP_CLAUSE_PRIVATE. + (gimplify_omp_for): Fix up handling of implicit + lastprivate or linear iterators. + (gimplify_omp_workshare): For OMP_TEAMS_COMBINED use + ORT_COMBINED_TEAMS. + * omp-low.c (lower_omp_for_lastprivate): For combined + for simd use fd.loop.n2 from the for rather than simd. + 2015-05-19 Richard Sandiford * config/cris/cris.c (cris_expand_prologue): Use gen_raw_REG diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index d573d7ab6d4..390400d7903 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,12 @@ +2015-05-19 Jakub Jelinek + + PR middle-end/66199 + * c-parser.c (c_parser_omp_for_loop): Don't add + OMP_CLAUSE_SHARED to OMP_PARALLEL_CLAUSES when moving + OMP_CLAUSE_LASTPRIVATE clause to OMP_FOR_CLAUSES. + (c_parser_omp_teams): Set OMP_TEAMS_COMBINED for combined + constructs. + 2015-05-19 Mikhail Maltsev * c-typeck.c (build_array_ref): Use std::swap instead of explicit diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 36438d02540..f496733b8a9 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -13100,12 +13100,9 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, } else { - /* Copy lastprivate (decl) clause to OMP_FOR_CLAUSES, - change it to shared (decl) in - OMP_PARALLEL_CLAUSES. */ - tree l = build_omp_clause (OMP_CLAUSE_LOCATION (*c), - OMP_CLAUSE_LASTPRIVATE); - OMP_CLAUSE_DECL (l) = OMP_CLAUSE_DECL (*c); + /* Move lastprivate (decl) clause to OMP_FOR_CLAUSES. */ + tree l = *c; + *c = OMP_CLAUSE_CHAIN (*c); if (code == OMP_SIMD) { OMP_CLAUSE_CHAIN (l) @@ -13117,7 +13114,6 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, OMP_CLAUSE_CHAIN (l) = clauses; clauses = l; } - OMP_CLAUSE_SET_CODE (*c, OMP_CLAUSE_SHARED); } } } @@ -13802,6 +13798,7 @@ c_parser_omp_teams (location_t loc, c_parser *parser, TREE_TYPE (ret) = void_type_node; OMP_TEAMS_CLAUSES (ret) = clauses; OMP_TEAMS_BODY (ret) = block; + OMP_TEAMS_COMBINED (ret) = 1; return add_stmt (ret); } } diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3271a5491f6..9a3fb854123 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2015-05-19 Jakub Jelinek + + PR middle-end/66199 + * parser.c (cp_parser_omp_for_loop): Don't add + OMP_CLAUSE_SHARED to OMP_PARALLEL_CLAUSES when moving + OMP_CLAUSE_LASTPRIVATE clause to OMP_FOR_CLAUSES. + (cp_parser_omp_teams): Set OMP_TEAMS_COMBINED for combined + constructs. + 2015-05-19 Mikhail Maltsev * typeck.c (composite_pointer_type): Use std::swap instead of explicit diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 432aa1cab93..4f429a2d60d 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -30493,11 +30493,9 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, else if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_LASTPRIVATE && OMP_CLAUSE_DECL (*c) == real_decl) { - /* Add lastprivate (decl) clause to OMP_FOR_CLAUSES, - change it to shared (decl) in OMP_PARALLEL_CLAUSES. */ - tree l = build_omp_clause (loc, OMP_CLAUSE_LASTPRIVATE); - OMP_CLAUSE_DECL (l) = real_decl; - CP_OMP_CLAUSE_INFO (l) = CP_OMP_CLAUSE_INFO (*c); + /* Move lastprivate (decl) clause to OMP_FOR_CLAUSES. */ + tree l = *c; + *c = OMP_CLAUSE_CHAIN (*c); if (code == OMP_SIMD) { OMP_CLAUSE_CHAIN (l) = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; @@ -30508,8 +30506,6 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, OMP_CLAUSE_CHAIN (l) = clauses; clauses = l; } - OMP_CLAUSE_SET_CODE (*c, OMP_CLAUSE_SHARED); - CP_OMP_CLAUSE_INFO (*c) = NULL; add_private_clause = false; } else @@ -31343,6 +31339,7 @@ cp_parser_omp_teams (cp_parser *parser, cp_token *pragma_tok, TREE_TYPE (ret) = void_type_node; OMP_TEAMS_CLAUSES (ret) = clauses; OMP_TEAMS_BODY (ret) = body; + OMP_TEAMS_COMBINED (ret) = 1; return add_stmt (ret); } } diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 2fc04fdc723..92d704afc67 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,11 @@ +2015-05-19 Jakub Jelinek + + PR middle-end/66199 + * trans-openmp.c (gfc_trans_omp_teams): Set OMP_TEAMS_COMBINED for + combined constructs. + (gfc_trans_omp_target): Make sure BIND_EXPR has non-NULL + BIND_EXPR_BLOCK. + 2015-05-19 David Malcolm * cpp.c (maybe_print_line): Strengthen local "map" from diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c index dd19a9cec21..9d95e86aa23 100644 --- a/gcc/fortran/trans-openmp.c +++ b/gcc/fortran/trans-openmp.c @@ -4116,6 +4116,7 @@ gfc_trans_omp_teams (gfc_code *code, gfc_omp_clauses *clausesa) stmtblock_t block; gfc_omp_clauses clausesa_buf[GFC_OMP_SPLIT_NUM]; tree stmt, omp_clauses = NULL_TREE; + bool combined = true; gfc_start_block (&block); if (clausesa == NULL) @@ -4132,6 +4133,7 @@ gfc_trans_omp_teams (gfc_code *code, gfc_omp_clauses *clausesa) case EXEC_OMP_TARGET_TEAMS: case EXEC_OMP_TEAMS: stmt = gfc_trans_omp_code (code->block->next, true); + combined = false; break; case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE: case EXEC_OMP_TEAMS_DISTRIBUTE: @@ -4145,6 +4147,8 @@ gfc_trans_omp_teams (gfc_code *code, gfc_omp_clauses *clausesa) } stmt = build2_loc (input_location, OMP_TEAMS, void_type_node, stmt, omp_clauses); + if (combined) + OMP_TEAMS_COMBINED (stmt) = 1; gfc_add_expr_to_block (&block, stmt); return gfc_finish_block (&block); } @@ -4165,9 +4169,14 @@ gfc_trans_omp_target (gfc_code *code) if (code->op == EXEC_OMP_TARGET) stmt = gfc_trans_omp_code (code->block->next, true); else - stmt = gfc_trans_omp_teams (code, clausesa); - if (TREE_CODE (stmt) != BIND_EXPR) - stmt = build3_v (BIND_EXPR, NULL, stmt, NULL_TREE); + { + pushlevel (); + stmt = gfc_trans_omp_teams (code, clausesa); + if (TREE_CODE (stmt) != BIND_EXPR) + stmt = build3_v (BIND_EXPR, NULL, stmt, poplevel (1, 0)); + else + poplevel (0, 0); + } if (flag_openmp) stmt = build2_loc (input_location, OMP_TARGET, void_type_node, stmt, omp_clauses); diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 7d53aa2c470..c5eccf06280 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -111,6 +111,9 @@ enum gimplify_omp_var_data /* Flag for GOVD_MAP: don't copy back. */ GOVD_MAP_TO_ONLY = 8192, + /* Flag for GOVD_LINEAR or GOVD_LASTPRIVATE: no outer reference. */ + GOVD_LINEAR_LASTPRIVATE_NO_OUTER = 16384, + GOVD_DATA_SHARE_CLASS = (GOVD_SHARED | GOVD_PRIVATE | GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LINEAR | GOVD_LOCAL) @@ -126,6 +129,7 @@ enum omp_region_type ORT_TASK = 4, ORT_UNTIED_TASK = 5, ORT_TEAMS = 8, + ORT_COMBINED_TEAMS = 9, /* Data region. */ ORT_TARGET_DATA = 16, /* Data region with offloading. */ @@ -5870,7 +5874,7 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code) DECL_NAME (lang_hooks.decls.omp_report_decl (decl))); error_at (ctx->location, "enclosing task"); } - else if (ctx->region_type == ORT_TEAMS) + else if (ctx->region_type & ORT_TEAMS) { error ("%qE not specified in enclosing teams construct", DECL_NAME (lang_hooks.decls.omp_report_decl (decl))); @@ -5963,6 +5967,13 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code) need to propagate anything to an outer context. */ if ((flags & GOVD_PRIVATE) && !(flags & GOVD_PRIVATE_OUTER_REF)) return ret; + if ((flags & (GOVD_LINEAR | GOVD_LINEAR_LASTPRIVATE_NO_OUTER)) + == (GOVD_LINEAR | GOVD_LINEAR_LASTPRIVATE_NO_OUTER)) + return ret; + if ((flags & (GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE + | GOVD_LINEAR_LASTPRIVATE_NO_OUTER)) + == (GOVD_LASTPRIVATE | GOVD_LINEAR_LASTPRIVATE_NO_OUTER)) + return ret; if (ctx->outer_context && omp_notice_variable (ctx->outer_context, decl, in_code)) return true; @@ -6062,6 +6073,36 @@ omp_check_private (struct gimplify_omp_ctx *ctx, tree decl, bool copyprivate) return false; } +/* Return true if the CTX is combined with distribute and thus + lastprivate can't be supported. */ + +static bool +omp_no_lastprivate (struct gimplify_omp_ctx *ctx) +{ + do + { + if (ctx->outer_context == NULL) + return false; + ctx = ctx->outer_context; + switch (ctx->region_type) + { + case ORT_WORKSHARE: + if (!ctx->combined_loop) + return false; + if (ctx->distribute) + return true; + break; + case ORT_COMBINED_PARALLEL: + break; + case ORT_COMBINED_TEAMS: + return true; + default: + return false; + } + } + while (1); +} + /* Scan the OMP clauses in *LIST_P, installing mappings into a new and previous omp contexts. */ @@ -6105,6 +6146,35 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_CLAUSE_LASTPRIVATE: flags = GOVD_LASTPRIVATE | GOVD_SEEN | GOVD_EXPLICIT; check_non_private = "lastprivate"; + decl = OMP_CLAUSE_DECL (c); + if (omp_no_lastprivate (ctx)) + { + notice_outer = false; + flags |= GOVD_LINEAR_LASTPRIVATE_NO_OUTER; + } + else if (error_operand_p (decl)) + goto do_add; + else if (outer_ctx + && outer_ctx->region_type == ORT_COMBINED_PARALLEL + && splay_tree_lookup (outer_ctx->variables, + (splay_tree_key) decl) == NULL) + omp_add_variable (outer_ctx, decl, GOVD_SHARED | GOVD_SEEN); + else if (outer_ctx + && outer_ctx->region_type == ORT_WORKSHARE + && outer_ctx->combined_loop + && splay_tree_lookup (outer_ctx->variables, + (splay_tree_key) decl) == NULL + && !omp_check_private (outer_ctx, decl, false)) + { + omp_add_variable (outer_ctx, decl, GOVD_LASTPRIVATE | GOVD_SEEN); + if (outer_ctx->outer_context + && (outer_ctx->outer_context->region_type + == ORT_COMBINED_PARALLEL) + && splay_tree_lookup (outer_ctx->outer_context->variables, + (splay_tree_key) decl) == NULL) + omp_add_variable (outer_ctx->outer_context, decl, + GOVD_SHARED | GOVD_SEEN); + } goto do_add; case OMP_CLAUSE_REDUCTION: flags = GOVD_REDUCTION | GOVD_SEEN | GOVD_EXPLICIT; @@ -6117,7 +6187,68 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, remove = true; break; } + else + { + /* For combined #pragma omp parallel for simd, need to put + lastprivate and perhaps firstprivate too on the + parallel. Similarly for #pragma omp for simd. */ + struct gimplify_omp_ctx *octx = outer_ctx; + decl = NULL_TREE; + if (omp_no_lastprivate (ctx)) + OMP_CLAUSE_LINEAR_NO_COPYOUT (c) = 1; + do + { + if (OMP_CLAUSE_LINEAR_NO_COPYIN (c) + && OMP_CLAUSE_LINEAR_NO_COPYOUT (c)) + break; + decl = OMP_CLAUSE_DECL (c); + if (error_operand_p (decl)) + { + decl = NULL_TREE; + break; + } + if (octx + && octx->region_type == ORT_WORKSHARE + && octx->combined_loop) + { + if (octx->outer_context + && (octx->outer_context->region_type + == ORT_COMBINED_PARALLEL + || (octx->outer_context->region_type + == ORT_COMBINED_TEAMS))) + octx = octx->outer_context; + else if (omp_check_private (octx, decl, false)) + break; + } + else + break; + gcc_checking_assert (splay_tree_lookup (octx->variables, + (splay_tree_key) + decl) == NULL); + flags = GOVD_SEEN; + if (!OMP_CLAUSE_LINEAR_NO_COPYIN (c)) + flags |= GOVD_FIRSTPRIVATE; + if (!OMP_CLAUSE_LINEAR_NO_COPYOUT (c)) + flags |= GOVD_LASTPRIVATE; + omp_add_variable (octx, decl, flags); + if (octx->outer_context == NULL) + break; + octx = octx->outer_context; + } + while (1); + if (octx + && decl + && (!OMP_CLAUSE_LINEAR_NO_COPYIN (c) + || !OMP_CLAUSE_LINEAR_NO_COPYOUT (c))) + omp_notice_variable (octx, decl, true); + } flags = GOVD_LINEAR | GOVD_EXPLICIT; + if (OMP_CLAUSE_LINEAR_NO_COPYIN (c) + && OMP_CLAUSE_LINEAR_NO_COPYOUT (c)) + { + notice_outer = false; + flags |= GOVD_LINEAR_LASTPRIVATE_NO_OUTER; + } goto do_add; case OMP_CLAUSE_MAP: @@ -6571,34 +6702,6 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, tree *list_p) OMP_CLAUSE_SET_CODE (c, OMP_CLAUSE_PRIVATE); OMP_CLAUSE_PRIVATE_DEBUG (c) = 1; } - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR - && ctx->outer_context - && !(OMP_CLAUSE_LINEAR_NO_COPYIN (c) - && OMP_CLAUSE_LINEAR_NO_COPYOUT (c))) - { - if (ctx->outer_context->combined_loop - && !OMP_CLAUSE_LINEAR_NO_COPYIN (c)) - { - n = splay_tree_lookup (ctx->outer_context->variables, - (splay_tree_key) decl); - if (n == NULL - || (n->value & GOVD_DATA_SHARE_CLASS) == 0) - { - int flags = GOVD_FIRSTPRIVATE; - /* #pragma omp distribute does not allow - lastprivate clause. */ - if (!ctx->outer_context->distribute) - flags |= GOVD_LASTPRIVATE; - if (n == NULL) - omp_add_variable (ctx->outer_context, decl, - flags | GOVD_SEEN); - else - n->value |= flags | GOVD_SEEN; - } - } - else if (!is_global_var (decl)) - omp_notice_variable (ctx->outer_context, decl, true); - } } break; @@ -6609,6 +6712,13 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, tree *list_p) n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c) = (n->value & GOVD_FIRSTPRIVATE) != 0; + if (omp_no_lastprivate (ctx)) + { + if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c)) + remove = true; + else + OMP_CLAUSE_CODE (c) = OMP_CLAUSE_PRIVATE; + } break; case OMP_CLAUSE_ALIGNED: @@ -6923,6 +7033,22 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) gcc_unreachable (); } + /* Set OMP_CLAUSE_LINEAR_NO_COPYIN flag on explicit linear + clause for the IV. */ + if (simd && TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) == 1) + { + t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), 0); + gcc_assert (TREE_CODE (t) == MODIFY_EXPR); + decl = TREE_OPERAND (t, 0); + for (tree c = OMP_FOR_CLAUSES (for_stmt); c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR + && OMP_CLAUSE_DECL (c) == decl) + { + OMP_CLAUSE_LINEAR_NO_COPYIN (c) = 1; + break; + } + } + gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p, simd ? ORT_SIMD : ORT_WORKSHARE); if (TREE_CODE (for_stmt) == OMP_DISTRIBUTE) @@ -6997,38 +7123,67 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) { c = build_omp_clause (input_location, OMP_CLAUSE_LINEAR); OMP_CLAUSE_LINEAR_NO_COPYIN (c) = 1; - if (has_decl_expr - && bitmap_bit_p (has_decl_expr, DECL_UID (decl))) - OMP_CLAUSE_LINEAR_NO_COPYOUT (c) = 1; + unsigned int flags = GOVD_LINEAR | GOVD_EXPLICIT | GOVD_SEEN; + if ((has_decl_expr + && bitmap_bit_p (has_decl_expr, DECL_UID (decl))) + || omp_no_lastprivate (gimplify_omp_ctxp)) + { + OMP_CLAUSE_LINEAR_NO_COPYOUT (c) = 1; + flags |= GOVD_LINEAR_LASTPRIVATE_NO_OUTER; + } OMP_CLAUSE_DECL (c) = decl; OMP_CLAUSE_CHAIN (c) = OMP_FOR_CLAUSES (for_stmt); OMP_FOR_CLAUSES (for_stmt) = c; - omp_add_variable (gimplify_omp_ctxp, decl, - GOVD_LINEAR | GOVD_EXPLICIT | GOVD_SEEN); + + omp_add_variable (gimplify_omp_ctxp, decl, flags); + struct gimplify_omp_ctx *outer + = gimplify_omp_ctxp->outer_context; + if (outer && !OMP_CLAUSE_LINEAR_NO_COPYOUT (c)) + { + if (outer->region_type == ORT_WORKSHARE + && outer->combined_loop) + { + if (outer->outer_context + && (outer->outer_context->region_type + == ORT_COMBINED_PARALLEL)) + outer = outer->outer_context; + else if (omp_check_private (outer, decl, false)) + outer = NULL; + } + else if (outer->region_type != ORT_COMBINED_PARALLEL) + outer = NULL; + if (outer) + { + omp_add_variable (outer, decl, + GOVD_LASTPRIVATE | GOVD_SEEN); + if (outer->outer_context) + omp_notice_variable (outer->outer_context, decl, true); + } + } } else { bool lastprivate = (!has_decl_expr - || !bitmap_bit_p (has_decl_expr, DECL_UID (decl))); - if (lastprivate - && gimplify_omp_ctxp->outer_context - && gimplify_omp_ctxp->outer_context->region_type - == ORT_WORKSHARE - && gimplify_omp_ctxp->outer_context->combined_loop - && !gimplify_omp_ctxp->outer_context->distribute) + || !bitmap_bit_p (has_decl_expr, DECL_UID (decl))) + && !omp_no_lastprivate (gimplify_omp_ctxp); + struct gimplify_omp_ctx *outer + = gimplify_omp_ctxp->outer_context; + if (outer && lastprivate) { - struct gimplify_omp_ctx *outer - = gimplify_omp_ctxp->outer_context; - n = splay_tree_lookup (outer->variables, - (splay_tree_key) decl); - if (n != NULL - && (n->value & GOVD_DATA_SHARE_CLASS) == GOVD_LOCAL) - lastprivate = false; - else if (omp_check_private (outer, decl, false)) - error ("lastprivate variable %qE is private in outer " - "context", DECL_NAME (decl)); - else + if (outer->region_type == ORT_WORKSHARE + && outer->combined_loop) + { + if (outer->outer_context + && (outer->outer_context->region_type + == ORT_COMBINED_PARALLEL)) + outer = outer->outer_context; + else if (omp_check_private (outer, decl, false)) + outer = NULL; + } + else if (outer->region_type != ORT_COMBINED_PARALLEL) + outer = NULL; + if (outer) { omp_add_variable (outer, decl, GOVD_LASTPRIVATE | GOVD_SEEN); @@ -7036,6 +7191,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) omp_notice_variable (outer->outer_context, decl, true); } } + c = build_omp_clause (input_location, lastprivate ? OMP_CLAUSE_LASTPRIVATE : OMP_CLAUSE_PRIVATE); @@ -7327,7 +7483,7 @@ gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p) ort = ORT_TARGET_DATA; break; case OMP_TEAMS: - ort = ORT_TEAMS; + ort = OMP_TEAMS_COMBINED (expr) ? ORT_COMBINED_TEAMS : ORT_TEAMS; break; default: gcc_unreachable (); diff --git a/gcc/omp-low.c b/gcc/omp-low.c index d352801c0ce..8290a651c9d 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -10538,7 +10538,21 @@ lower_omp_for_lastprivate (struct omp_for_data *fd, gimple_seq *body_p, cond_code = EQ_EXPR; } - cond = build2 (cond_code, boolean_type_node, fd->loop.v, fd->loop.n2); + tree n2 = fd->loop.n2; + if (fd->collapse > 1 + && TREE_CODE (n2) != INTEGER_CST + && gimple_omp_for_combined_into_p (fd->for_stmt) + && gimple_code (ctx->outer->stmt) == GIMPLE_OMP_FOR) + { + gomp_for *gfor = as_a (ctx->outer->stmt); + if (gimple_omp_for_kind (gfor) == GF_OMP_FOR_KIND_FOR) + { + struct omp_for_data outer_fd; + extract_omp_for_data (gfor, &outer_fd, NULL); + n2 = fold_convert (TREE_TYPE (n2), outer_fd.loop.n2); + } + } + cond = build2 (cond_code, boolean_type_node, fd->loop.v, n2); clauses = gimple_omp_for_clauses (fd->for_stmt); stmts = NULL; diff --git a/gcc/tree.h b/gcc/tree.h index 912b05405d8..1d88e297d63 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1326,6 +1326,11 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_PARALLEL_COMBINED(NODE) \ (OMP_PARALLEL_CHECK (NODE)->base.private_flag) +/* True on an OMP_TEAMS statement if it represents an explicit + combined teams distribute constructs. */ +#define OMP_TEAMS_COMBINED(NODE) \ + (OMP_TEAMS_CHECK (NODE)->base.private_flag) + /* True if OMP_ATOMIC* is supposed to be sequentially consistent as opposed to relaxed. */ #define OMP_ATOMIC_SEQ_CST(NODE) \ diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog index 60ad7f50817..10771ab54e6 100644 --- a/libgomp/ChangeLog +++ b/libgomp/ChangeLog @@ -1,3 +1,13 @@ +2015-05-19 Jakub Jelinek + + PR middle-end/66199 + * testsuite/libgomp.c/pr66199-1.c: New test. + * testsuite/libgomp.c/pr66199-2.c: New test. + * testsuite/libgomp.c++/pr66199-1.C: New test. + * testsuite/libgomp.c++/pr66199-2.C: New test. + * testsuite/libgomp.fortran/pr66199-1.f90: New test. + * testsuite/libgomp.fortran/pr66199-2.f90: New test. + 2015-05-19 Julian Brown * plugin/plugin-nvptx.c (nvptx_get_num_devices): Return zero diff --git a/libgomp/testsuite/libgomp.c++/pr66199-1.C b/libgomp/testsuite/libgomp.c++/pr66199-1.C new file mode 100644 index 00000000000..2139e11b51c --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/pr66199-1.C @@ -0,0 +1,5 @@ +// PR middle-end/66199 +// { dg-do run } +// { dg-options "-O2 -fopenmp" } + +#include "../libgomp.c/pr66199-1.c" diff --git a/libgomp/testsuite/libgomp.c++/pr66199-2.C b/libgomp/testsuite/libgomp.c++/pr66199-2.C new file mode 100644 index 00000000000..36392da270a --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/pr66199-2.C @@ -0,0 +1,5 @@ +// PR middle-end/66199 +// { dg-do run } +// { dg-options "-O2 -fopenmp" } + +#include "../libgomp.c/pr66199-2.c" diff --git a/libgomp/testsuite/libgomp.c/pr66199-1.c b/libgomp/testsuite/libgomp.c/pr66199-1.c new file mode 100644 index 00000000000..6fd9f87fa24 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/pr66199-1.c @@ -0,0 +1,62 @@ +/* PR middle-end/66199 */ +/* { dg-do run } */ +/* { dg-options "-O2 -fopenmp" } */ + +int u[1024], v[1024], w[1024]; + +__attribute__((noinline, noclone)) long +f1 (long a, long b) +{ + long d; + #pragma omp parallel for simd default(none) firstprivate (a, b) shared(u, v, w) + for (d = a; d < b; d++) + u[d] = v[d] + w[d]; + return d; +} + +__attribute__((noinline, noclone)) long +f2 (long a, long b, long c) +{ + long d, e; + #pragma omp parallel for simd default(none) firstprivate (a, b) shared(u, v, w) linear(d) linear(c:5) lastprivate(e) + for (d = a; d < b; d++) + { + u[d] = v[d] + w[d]; + c += 5; + e = c; + } + return d + c + e; +} + +__attribute__((noinline, noclone)) long +f3 (long a1, long b1, long a2, long b2) +{ + long d1, d2; + #pragma omp parallel for simd default(none) firstprivate (a1, b1, a2, b2) shared(u, v, w) lastprivate(d1, d2) collapse(2) + for (d1 = a1; d1 < b1; d1++) + for (d2 = a2; d2 < b2; d2++) + u[d1 * 32 + d2] = v[d1 * 32 + d2] + w[d1 * 32 + d2]; + return d1 + d2; +} + +__attribute__((noinline, noclone)) long +f4 (long a1, long b1, long a2, long b2) +{ + long d1, d2; + #pragma omp parallel for simd default(none) firstprivate (a1, b1, a2, b2) shared(u, v, w) collapse(2) + for (d1 = a1; d1 < b1; d1++) + for (d2 = a2; d2 < b2; d2++) + u[d1 * 32 + d2] = v[d1 * 32 + d2] + w[d1 * 32 + d2]; + return d1 + d2; +} + +int +main () +{ + if (f1 (0, 1024) != 1024 + || f2 (0, 1024, 17) != 1024 + 2 * (17 + 5 * 1024) + || f3 (0, 32, 0, 32) != 64 + || f4 (0, 32, 0, 32) != 64) + __builtin_abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/pr66199-2.c b/libgomp/testsuite/libgomp.c/pr66199-2.c new file mode 100644 index 00000000000..dbcd701b755 --- /dev/null +++ b/libgomp/testsuite/libgomp.c/pr66199-2.c @@ -0,0 +1,59 @@ +/* PR middle-end/66199 */ +/* { dg-do run } */ +/* { dg-options "-O2 -fopenmp" } */ + +#pragma omp declare target +int u[1024], v[1024], w[1024]; +#pragma omp end declare target + +__attribute__((noinline, noclone)) void +f1 (long a, long b) +{ + long d; + #pragma omp target teams distribute parallel for simd default(none) firstprivate (a, b) shared(u, v, w) + for (d = a; d < b; d++) + u[d] = v[d] + w[d]; +} + +__attribute__((noinline, noclone)) void +f2 (long a, long b, long c) +{ + long d, e; + #pragma omp target teams distribute parallel for simd default(none) firstprivate (a, b) shared(u, v, w) linear(d) linear(c:5) lastprivate(e) + for (d = a; d < b; d++) + { + u[d] = v[d] + w[d]; + c += 5; + e = c; + } +} + +__attribute__((noinline, noclone)) void +f3 (long a1, long b1, long a2, long b2) +{ + long d1, d2; + #pragma omp target teams distribute parallel for simd default(none) firstprivate (a1, b1, a2, b2) shared(u, v, w) lastprivate(d1, d2) collapse(2) + for (d1 = a1; d1 < b1; d1++) + for (d2 = a2; d2 < b2; d2++) + u[d1 * 32 + d2] = v[d1 * 32 + d2] + w[d1 * 32 + d2]; +} + +__attribute__((noinline, noclone)) void +f4 (long a1, long b1, long a2, long b2) +{ + long d1, d2; + #pragma omp target teams distribute parallel for simd default(none) firstprivate (a1, b1, a2, b2) shared(u, v, w) collapse(2) + for (d1 = a1; d1 < b1; d1++) + for (d2 = a2; d2 < b2; d2++) + u[d1 * 32 + d2] = v[d1 * 32 + d2] + w[d1 * 32 + d2]; +} + +int +main () +{ + f1 (0, 1024); + f2 (0, 1024, 17); + f3 (0, 32, 0, 32); + f4 (0, 32, 0, 32); + return 0; +} diff --git a/libgomp/testsuite/libgomp.fortran/pr66199-1.f90 b/libgomp/testsuite/libgomp.fortran/pr66199-1.f90 new file mode 100644 index 00000000000..0cd232f3e14 --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/pr66199-1.f90 @@ -0,0 +1,49 @@ +! PR middle-end/66199 +! { dg-do run } +! { dg-options "-O2 -fopenmp" } + + integer :: u(1024), v(1024), w(1024), a, b, c, d, e, a1, b1, a2, b2, d1, d2 + a = 1 + b = 1024 + d = 75 + !$omp parallel do simd default(none) firstprivate (a, b) shared(u, v, w) + do d = a, b + u(d) = v(d) + w(d) + end do + if (d .ne. 1025) call abort + c = 17 + d = 75 + !$omp parallel do simd default(none) firstprivate (a, b) shared(u, v, w) & + !$omp& linear(d) linear(c:5) lastprivate(e) + do d = a, b + u(d) = v(d) + w(d) + c = c + 5 + e = c + end do + if (d .ne. 1025 .or. c .ne. (17 + 5 * 1024)) call abort + if (e .ne. (17 + 5 * 1024)) call abort + a1 = 0 + a2 = 0 + b1 = 31 + b2 = 31 + d1 = 7 + d2 = 9 + !$omp parallel do simd default(none) firstprivate (a1, b1, a2, b2) & + !$omp& shared(u, v, w) lastprivate(d1, d2) collapse(2) + do d1 = a1, b1 + do d2 = a2, b2 + u(d1 * 32 + d2 + 1) = v(d1 * 32 + d2 + 1) + w(d1 * 32 + d2 + 1) + end do + end do + if (d1 .ne. 32 .or. d2 .ne. 32) call abort + d1 = 7 + d2 = 9 + !$omp parallel do simd default(none) firstprivate (a1, b1, a2, b2) & + !$omp& shared(u, v, w) collapse(2) + do d1 = a1, b1 + do d2 = a2, b2 + u(d1 * 32 + d2 + 1) = v(d1 * 32 + d2 + 1) + w(d1 * 32 + d2 + 1) + end do + end do + if (d1 .ne. 32 .or. d2 .ne. 32) call abort +end diff --git a/libgomp/testsuite/libgomp.fortran/pr66199-2.f90 b/libgomp/testsuite/libgomp.fortran/pr66199-2.f90 new file mode 100644 index 00000000000..ad11eade72c --- /dev/null +++ b/libgomp/testsuite/libgomp.fortran/pr66199-2.f90 @@ -0,0 +1,47 @@ +! PR middle-end/66199 +! { dg-do run } +! { dg-options "-O2 -fopenmp" } + + integer :: u(1024), v(1024), w(1024), a, b, c, d, e, a1, b1, a2, b2, d1, d2 + a = 1 + b = 1024 + d = 75 + !$omp target teams distribute parallel do simd default(none) & + !$omp& firstprivate (a, b) shared(u, v, w) + do d = a, b + u(d) = v(d) + w(d) + end do + c = 17 + d = 75 + !$omp target teams distribute parallel do simd default(none) & + !$omp& firstprivate (a, b) shared(u, v, w) & + !$omp& linear(d) linear(c:5) lastprivate(e) + do d = a, b + u(d) = v(d) + w(d) + c = c + 5 + e = c + end do + a1 = 0 + a2 = 0 + b1 = 31 + b2 = 31 + d1 = 7 + d2 = 9 + !$omp target teams distribute parallel do simd default(none) & + !$omp& firstprivate (a1, b1, a2, b2) & + !$omp& shared(u, v, w) lastprivate(d1, d2) collapse(2) + do d1 = a1, b1 + do d2 = a2, b2 + u(d1 * 32 + d2 + 1) = v(d1 * 32 + d2 + 1) + w(d1 * 32 + d2 + 1) + end do + end do + d1 = 7 + d2 = 9 + !$omp target teams distribute parallel do simd default(none) & + !$omp& firstprivate (a1, b1, a2, b2) shared(u, v, w) collapse(2) + do d1 = a1, b1 + do d2 = a2, b2 + u(d1 * 32 + d2 + 1) = v(d1 * 32 + d2 + 1) + w(d1 * 32 + d2 + 1) + end do + end do +end -- 2.30.2