From d81ab49d0586fca0f3ee2f49c4581dd02508fcca Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 6 Aug 2019 09:26:32 +0200 Subject: [PATCH] tree.h (OMP_CLAUSE_LASTPRIVATE_TASKLOOP_IV): Rename to ... * tree.h (OMP_CLAUSE_LASTPRIVATE_TASKLOOP_IV): Rename to ... (OMP_CLAUSE_LASTPRIVATE_LOOP_IV): ... this. Adjust comment. * gimplify.c (gimple_add_tmp_var): In SIMD contexts, turn addressable new vars into GOVD_PRIVATE rather than GOVD_LOCAL. (gimplify_omp_for): Don't do C++ random access iterator clause adjustments on combined constructs from OMP_LOOP. For OMP_LOOP, don't predetermine the artificial iterator in case of C++ random access iterators as lastprivate, but private. For OMP_LOOP, force bind expr around simd body and force for_pre_body before the construct. Use OMP_CLAUSE_LASTPRIVATE_LOOP_IV instead of OMP_CLAUSE_LASTPRIVATE_TASKLOOP_IV. (gimplify_omp_loop): Add firstprivate clauses on OMP_PARALLEL for diff var of C++ random access iterators. Handle OMP_CLAUSE_FIRSTPRIVATE. For OMP_CLAUSE_LASTPRIVATE_LOOP_IV, if not outermost also add OMP_CLAUSE_FIRSTPRIVATE, and in both cases clear OMP_CLAUSE_LASTPRIVATE_LOOP_IV on the lastprivate clause on the OMP_FOR and OMP_DISTRIBUTE constructs if any. * omp-low.c (lower_rec_input_clauses): For OMP_CLAUSE_LASTPRIVATE_LOOP_IV on simd copy construct the private variables instead of default constructing them. (lower_lastprivate_clauses): Use OMP_CLAUSE_LASTPRIVATE_LOOP_IV instead of OMP_CLAUSE_LASTPRIVATE_TASKLOOP_IV and move the is_taskloop_ctx check from the assert to the guarding condition. gcc/cp/ * parser.c (cp_parser_omp_for_loop): For OMP_LOOP, ignore parallel clauses and predetermine iterator as lastprivate. * semantics.c (handle_omp_for_class_iterator): Use OMP_CLAUSE_LASTPRIVATE_LOOP_IV instead of OMP_CLAUSE_LASTPRIVATE_TASKLOOP_IV, set it for lastprivate also on OMP_LOOP construct. If a clause is missing for class iterator on OMP_LOOP, add firstprivate clause, and if there is private clause, turn it into firstprivate too. (finish_omp_for): Formatting fix. For OMP_LOOP, adjust OMP_CLAUSE_LASTPRIVATE_LOOP_IV clause CP_CLAUSE_INFO, so that it uses copy ctor instead of default ctor. * cp-gimplify.c (cp_gimplify_expr): Handle OMP_LOOP like OMP_DISTRIBUTE etc. (cp_fold_r): Likewise. (cp_genericize_r): Likewise. (cxx_omp_finish_clause): Also finish lastprivate clause with OMP_CLAUSE_LASTPRIVATE_LOOP_IV flag. * pt.c (tsubst_omp_clauses): Handle OMP_CLAUSE_BIND. (tsubst_omp_for_iterator): For OMP_LOOP, ignore parallel clauses and predetermine iterator as lastprivate. * constexpr.c (potential_constant_expression_1): Handle OMP_LOOP like OMP_DISTRIBUTE etc. libgomp/ * testsuite/libgomp.c++/loop-13.C: New test. * testsuite/libgomp.c++/loop-14.C: New test. * testsuite/libgomp.c++/loop-15.C: New test. From-SVN: r274138 --- gcc/ChangeLog | 26 ++ gcc/cp/ChangeLog | 25 ++ gcc/cp/constexpr.c | 1 + gcc/cp/cp-gimplify.c | 12 +- gcc/cp/parser.c | 11 +- gcc/cp/pt.c | 9 +- gcc/cp/semantics.c | 53 ++- gcc/gimplify.c | 80 ++++- gcc/omp-low.c | 29 +- gcc/tree.h | 9 +- libgomp/ChangeLog | 6 + libgomp/testsuite/libgomp.c++/loop-13.C | 298 +++++++++++++++++ libgomp/testsuite/libgomp.c++/loop-14.C | 301 +++++++++++++++++ libgomp/testsuite/libgomp.c++/loop-15.C | 417 ++++++++++++++++++++++++ 14 files changed, 1237 insertions(+), 40 deletions(-) create mode 100644 libgomp/testsuite/libgomp.c++/loop-13.C create mode 100644 libgomp/testsuite/libgomp.c++/loop-14.C create mode 100644 libgomp/testsuite/libgomp.c++/loop-15.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f19091cf26e..ccb7253c480 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,29 @@ +2019-08-06 Jakub Jelinek + + * tree.h (OMP_CLAUSE_LASTPRIVATE_TASKLOOP_IV): Rename to ... + (OMP_CLAUSE_LASTPRIVATE_LOOP_IV): ... this. Adjust comment. + * gimplify.c (gimple_add_tmp_var): In SIMD contexts, turn addressable + new vars into GOVD_PRIVATE rather than GOVD_LOCAL. + (gimplify_omp_for): Don't do C++ random access iterator clause + adjustments on combined constructs from OMP_LOOP. For OMP_LOOP, + don't predetermine the artificial iterator in case of C++ random + access iterators as lastprivate, but private. For OMP_LOOP, force + bind expr around simd body and force for_pre_body before the + construct. Use OMP_CLAUSE_LASTPRIVATE_LOOP_IV instead of + OMP_CLAUSE_LASTPRIVATE_TASKLOOP_IV. + (gimplify_omp_loop): Add firstprivate clauses on OMP_PARALLEL for + diff var of C++ random access iterators. Handle + OMP_CLAUSE_FIRSTPRIVATE. For OMP_CLAUSE_LASTPRIVATE_LOOP_IV, if + not outermost also add OMP_CLAUSE_FIRSTPRIVATE, and in both cases + clear OMP_CLAUSE_LASTPRIVATE_LOOP_IV on the lastprivate clause + on the OMP_FOR and OMP_DISTRIBUTE constructs if any. + * omp-low.c (lower_rec_input_clauses): For + OMP_CLAUSE_LASTPRIVATE_LOOP_IV on simd copy construct the private + variables instead of default constructing them. + (lower_lastprivate_clauses): Use OMP_CLAUSE_LASTPRIVATE_LOOP_IV + instead of OMP_CLAUSE_LASTPRIVATE_TASKLOOP_IV and move the + is_taskloop_ctx check from the assert to the guarding condition. + 2019-08-06 Kito Cheng * gcc/config/riscv/multilib-generator: (canonical_order): New. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 049863edf8e..98e3b3f41d8 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,28 @@ +2019-08-06 Jakub Jelinek + + * parser.c (cp_parser_omp_for_loop): For OMP_LOOP, ignore parallel + clauses and predetermine iterator as lastprivate. + * semantics.c (handle_omp_for_class_iterator): Use + OMP_CLAUSE_LASTPRIVATE_LOOP_IV instead of + OMP_CLAUSE_LASTPRIVATE_TASKLOOP_IV, set it for lastprivate also + on OMP_LOOP construct. If a clause is missing for class iterator + on OMP_LOOP, add firstprivate clause, and if there is private + clause, turn it into firstprivate too. + (finish_omp_for): Formatting fix. For OMP_LOOP, adjust + OMP_CLAUSE_LASTPRIVATE_LOOP_IV clause CP_CLAUSE_INFO, so that it + uses copy ctor instead of default ctor. + * cp-gimplify.c (cp_gimplify_expr): Handle OMP_LOOP like + OMP_DISTRIBUTE etc. + (cp_fold_r): Likewise. + (cp_genericize_r): Likewise. + (cxx_omp_finish_clause): Also finish lastprivate clause with + OMP_CLAUSE_LASTPRIVATE_LOOP_IV flag. + * pt.c (tsubst_omp_clauses): Handle OMP_CLAUSE_BIND. + (tsubst_omp_for_iterator): For OMP_LOOP, ignore parallel + clauses and predetermine iterator as lastprivate. + * constexpr.c (potential_constant_expression_1): Handle OMP_LOOP + like OMP_DISTRIBUTE etc. + 2019-08-05 Marek Polacek DR 2413 - typename in conversion-function-ids. diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 75df9844dc6..36a66337433 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -6437,6 +6437,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case OMP_SIMD: case OMP_DISTRIBUTE: case OMP_TASKLOOP: + case OMP_LOOP: case OMP_TEAMS: case OMP_TARGET_DATA: case OMP_TARGET: diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index b4863e2d592..065dcb7ba06 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -796,6 +796,7 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) case OMP_FOR: case OMP_SIMD: case OMP_DISTRIBUTE: + case OMP_LOOP: case OMP_TASKLOOP: ret = cp_gimplify_omp_for (expr_p, pre_p); break; @@ -1053,7 +1054,7 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data) code = TREE_CODE (stmt); if (code == OMP_FOR || code == OMP_SIMD || code == OMP_DISTRIBUTE - || code == OMP_TASKLOOP || code == OACC_LOOP) + || code == OMP_LOOP || code == OMP_TASKLOOP || code == OACC_LOOP) { tree x; int i, n; @@ -1544,6 +1545,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) case OMP_FOR: case OMP_SIMD: case OMP_DISTRIBUTE: + case OMP_LOOP: case OACC_LOOP: genericize_omp_for_stmt (stmt_p, walk_subtrees, data); break; @@ -2097,7 +2099,9 @@ cxx_omp_finish_clause (tree c, gimple_seq *) tree decl, inner_type; bool make_shared = false; - if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_FIRSTPRIVATE) + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_FIRSTPRIVATE + && (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_LASTPRIVATE + || !OMP_CLAUSE_LASTPRIVATE_LOOP_IV (c))) return; decl = OMP_CLAUSE_DECL (c); @@ -2115,9 +2119,11 @@ cxx_omp_finish_clause (tree c, gimple_seq *) /* Check for special function availability by building a call to one. Save the results, because later we won't be in the right context for making these queries. */ + bool first = OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE; if (!make_shared && CLASS_TYPE_P (inner_type) - && cxx_omp_create_clause_info (c, inner_type, false, true, false, true)) + && cxx_omp_create_clause_info (c, inner_type, !first, first, !first, + true)) make_shared = true; if (make_shared) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 83e6d24a9c1..79da7b52eb9 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -37458,7 +37458,8 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, real_decl = decl; if (cclauses != NULL && cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] != NULL - && real_decl != NULL_TREE) + && real_decl != NULL_TREE + && code != OMP_LOOP) { tree *c; for (c = &cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; *c ; ) @@ -37518,12 +37519,12 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, } if (c == NULL) { - if (code != OMP_SIMD) + if ((code == OMP_SIMD && collapse != 1) || code == OMP_LOOP) + c = build_omp_clause (loc, OMP_CLAUSE_LASTPRIVATE); + else if (code != OMP_SIMD) c = build_omp_clause (loc, OMP_CLAUSE_PRIVATE); - else if (collapse == 1) - c = build_omp_clause (loc, OMP_CLAUSE_LINEAR); else - c = build_omp_clause (loc, OMP_CLAUSE_LASTPRIVATE); + c = build_omp_clause (loc, OMP_CLAUSE_LINEAR); OMP_CLAUSE_DECL (c) = add_private_clause; c = finish_omp_clauses (c, C_ORT_OMP); if (c) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index e671fe1a91d..903e589b663 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -16404,6 +16404,7 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort, case OMP_CLAUSE_SIMD: case OMP_CLAUSE_DEFAULTMAP: case OMP_CLAUSE_ORDER: + case OMP_CLAUSE_BIND: case OMP_CLAUSE_INDEPENDENT: case OMP_CLAUSE_AUTO: case OMP_CLAUSE_SEQ: @@ -16732,7 +16733,8 @@ tsubst_omp_for_iterator (tree t, int i, tree declv, tree &orig_declv, { tree *pc; int j; - for (j = (omp_parallel_combined_clauses == NULL ? 1 : 0); j < 2; j++) + for (j = ((omp_parallel_combined_clauses == NULL + || TREE_CODE (t) == OMP_LOOP) ? 1 : 0); j < 2; j++) { for (pc = j ? clauses : omp_parallel_combined_clauses; *pc; ) { @@ -16772,7 +16774,10 @@ tsubst_omp_for_iterator (tree t, int i, tree declv, tree &orig_declv, } if (*pc == NULL_TREE) { - tree c = build_omp_clause (input_location, OMP_CLAUSE_PRIVATE); + tree c = build_omp_clause (input_location, + TREE_CODE (t) == OMP_LOOP + ? OMP_CLAUSE_LASTPRIVATE + : OMP_CLAUSE_PRIVATE); OMP_CLAUSE_DECL (c) = decl; c = finish_omp_clauses (c, C_ORT_OMP); if (c) diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index d151d3d4798..fa6962454bf 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -8422,24 +8422,25 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code, incr = cp_convert (TREE_TYPE (diff), incr, tf_warning_or_error); incr = cp_fully_fold (incr); - bool taskloop_iv_seen = false; + tree loop_iv_seen = NULL_TREE; for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c)) if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE && OMP_CLAUSE_DECL (c) == iter) { - if (code == OMP_TASKLOOP) + if (code == OMP_TASKLOOP || code == OMP_LOOP) { - taskloop_iv_seen = true; - OMP_CLAUSE_LASTPRIVATE_TASKLOOP_IV (c) = 1; + loop_iv_seen = c; + OMP_CLAUSE_LASTPRIVATE_LOOP_IV (c) = 1; } break; } - else if (code == OMP_TASKLOOP + else if ((code == OMP_TASKLOOP || code == OMP_LOOP) && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE && OMP_CLAUSE_DECL (c) == iter) { - taskloop_iv_seen = true; - OMP_CLAUSE_PRIVATE_TASKLOOP_IV (c) = 1; + loop_iv_seen = c; + if (code == OMP_TASKLOOP) + OMP_CLAUSE_PRIVATE_TASKLOOP_IV (c) = 1; } decl = create_temporary_var (TREE_TYPE (diff)); @@ -8459,7 +8460,7 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code, tree diffvar = NULL_TREE; if (code == OMP_TASKLOOP) { - if (!taskloop_iv_seen) + if (!loop_iv_seen) { tree ivc = build_omp_clause (locus, OMP_CLAUSE_FIRSTPRIVATE); OMP_CLAUSE_DECL (ivc) = iter; @@ -8475,6 +8476,28 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code, pushdecl (diffvar); add_decl_expr (diffvar); } + else if (code == OMP_LOOP) + { + if (!loop_iv_seen) + { + /* While iterators on the loop construct are predetermined + lastprivate, if the decl is not declared inside of the + loop, OMP_CLAUSE_LASTPRIVATE should have been added + already. */ + loop_iv_seen = build_omp_clause (locus, OMP_CLAUSE_FIRSTPRIVATE); + OMP_CLAUSE_DECL (loop_iv_seen) = iter; + OMP_CLAUSE_CHAIN (loop_iv_seen) = clauses; + clauses = loop_iv_seen; + } + else if (OMP_CLAUSE_CODE (loop_iv_seen) == OMP_CLAUSE_PRIVATE) + { + OMP_CLAUSE_PRIVATE_DEBUG (loop_iv_seen) = 0; + OMP_CLAUSE_PRIVATE_OUTER_REF (loop_iv_seen) = 0; + OMP_CLAUSE_CODE (loop_iv_seen) = OMP_CLAUSE_FIRSTPRIVATE; + } + if (OMP_CLAUSE_CODE (loop_iv_seen) == OMP_CLAUSE_FIRSTPRIVATE) + cxx_omp_finish_clause (loop_iv_seen, NULL); + } orig_pre_body = *pre_body; *pre_body = push_stmt_list (); @@ -8825,9 +8848,7 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv, omp_for = NULL_TREE; if (omp_for == NULL) - { - return NULL; - } + return NULL; add_stmt (omp_for); @@ -8926,6 +8947,16 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv, gcc_unreachable (); } } + /* Override saved methods on OMP_LOOP's OMP_CLAUSE_LASTPRIVATE_LOOP_IV + clauses, we need copy ctor for those rather than default ctor, + plus as for other lastprivates assignment op and dtor. */ + if (code == OMP_LOOP && !processing_template_decl) + for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE + && OMP_CLAUSE_LASTPRIVATE_LOOP_IV (c) + && cxx_omp_create_clause_info (c, TREE_TYPE (OMP_CLAUSE_DECL (c)), + false, true, true, true)) + CP_OMP_CLAUSE_INFO (c) = NULL_TREE; return omp_for; } diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 6a1a7f0b1ac..10b9b68d5ce 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -775,14 +775,27 @@ gimple_add_tmp_var (tree tmp) if (gimplify_omp_ctxp) { struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp; + int flag = GOVD_LOCAL; while (ctx && (ctx->region_type == ORT_WORKSHARE || ctx->region_type == ORT_TASKGROUP || ctx->region_type == ORT_SIMD || ctx->region_type == ORT_ACC)) - ctx = ctx->outer_context; + { + if (ctx->region_type == ORT_SIMD + && TREE_ADDRESSABLE (tmp) + && !TREE_STATIC (tmp)) + { + if (TREE_CODE (DECL_SIZE_UNIT (tmp)) != INTEGER_CST) + ctx->add_safelen1 = true; + else + flag = GOVD_PRIVATE; + break; + } + ctx = ctx->outer_context; + } if (ctx) - omp_add_variable (ctx, tmp, GOVD_LOCAL | GOVD_SEEN); + omp_add_variable (ctx, tmp, flag | GOVD_SEEN); } } else if (cfun) @@ -10590,6 +10603,8 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) orig_for_stmt = for_stmt = *expr_p; + bool loop_p = (omp_find_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_BIND) + != NULL_TREE); if (OMP_FOR_INIT (for_stmt) == NULL_TREE) { tree *data[4] = { NULL, NULL, NULL, NULL }; @@ -10641,7 +10656,8 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) } for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (inner_for_stmt)); i++) - if (OMP_FOR_ORIG_DECLS (inner_for_stmt) + if (!loop_p + && OMP_FOR_ORIG_DECLS (inner_for_stmt) && TREE_CODE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner_for_stmt), i)) == TREE_LIST && TREE_PURPOSE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner_for_stmt), @@ -10649,7 +10665,9 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) { tree orig = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner_for_stmt), i); /* Class iterators aren't allowed on OMP_SIMD, so the only - case we need to solve is distribute parallel for. */ + case we need to solve is distribute parallel for. They are + allowed on the loop construct, but that is already handled + in gimplify_omp_loop. */ gcc_assert (TREE_CODE (inner_for_stmt) == OMP_FOR && TREE_CODE (for_stmt) == OMP_DISTRIBUTE && data[1]); @@ -10791,8 +10809,6 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) } } - bool loop_p = (omp_find_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_BIND) - != NULL_TREE); if (TREE_CODE (for_stmt) != OMP_TASKLOOP) gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p, ort, loop_p && TREE_CODE (for_stmt) != OMP_SIMD @@ -11163,6 +11179,13 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) || !bitmap_bit_p (has_decl_expr, DECL_UID (decl))); if (TREE_PRIVATE (t)) lastprivate = false; + if (loop_p && OMP_FOR_ORIG_DECLS (for_stmt)) + { + tree elt = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt), i); + if (TREE_CODE (elt) == TREE_LIST && TREE_PURPOSE (elt)) + lastprivate = false; + } + struct gimplify_omp_ctx *outer = gimplify_omp_ctxp->outer_context; if (outer && lastprivate) @@ -11485,7 +11508,8 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) BITMAP_FREE (has_decl_expr); - if (TREE_CODE (orig_for_stmt) == OMP_TASKLOOP) + if (TREE_CODE (orig_for_stmt) == OMP_TASKLOOP + || (loop_p && orig_for_stmt == for_stmt)) { push_gimplify_context (); if (TREE_CODE (OMP_FOR_BODY (orig_for_stmt)) != BIND_EXPR) @@ -11500,7 +11524,8 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) gimple *g = gimplify_and_return_first (OMP_FOR_BODY (orig_for_stmt), &for_body); - if (TREE_CODE (orig_for_stmt) == OMP_TASKLOOP) + if (TREE_CODE (orig_for_stmt) == OMP_TASKLOOP + || (loop_p && orig_for_stmt == for_stmt)) { if (gimple_code (g) == GIMPLE_BIND) pop_gimplify_context (g); @@ -11540,6 +11565,11 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) default: gcc_unreachable (); } + if (loop_p && kind == GF_OMP_FOR_KIND_SIMD) + { + gimplify_seq_add_seq (pre_p, for_pre_body); + for_pre_body = NULL; + } gfor = gimple_build_omp_for (for_body, kind, OMP_FOR_CLAUSES (orig_for_stmt), TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)), for_pre_body); @@ -11640,7 +11670,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) a shared clause on task. If the same decl is also firstprivate, add also firstprivate clause on the inner taskloop. */ case OMP_CLAUSE_LASTPRIVATE: - if (OMP_CLAUSE_LASTPRIVATE_TASKLOOP_IV (c)) + if (OMP_CLAUSE_LASTPRIVATE_LOOP_IV (c)) { /* For taskloop C++ lastprivate IVs, we want: 1) private on outer taskloop @@ -11963,6 +11993,21 @@ gimplify_omp_loop (tree *expr_p, gimple_seq *pre_p) OMP_PARALLEL_BODY (*expr_p) = bind; OMP_PARALLEL_COMBINED (*expr_p) = 1; SET_EXPR_LOCATION (*expr_p, EXPR_LOCATION (for_stmt)); + tree *pc = &OMP_PARALLEL_CLAUSES (*expr_p); + for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++) + if (OMP_FOR_ORIG_DECLS (for_stmt) + && (TREE_CODE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt), i)) + == TREE_LIST)) + { + tree elt = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt), i); + if (TREE_PURPOSE (elt) && TREE_VALUE (elt)) + { + *pc = build_omp_clause (UNKNOWN_LOCATION, + OMP_CLAUSE_FIRSTPRIVATE); + OMP_CLAUSE_DECL (*pc) = TREE_VALUE (elt); + pc = &OMP_CLAUSE_CHAIN (*pc); + } + } } tree t = make_node (pass == 2 ? OMP_DISTRIBUTE : OMP_FOR); tree *pc = &OMP_FOR_CLAUSES (t); @@ -11979,12 +12024,29 @@ gimplify_omp_loop (tree *expr_p, gimple_seq *pre_p) pc = &OMP_CLAUSE_CHAIN (*pc); break; case OMP_CLAUSE_PRIVATE: + case OMP_CLAUSE_FIRSTPRIVATE: /* Only needed on innermost. */ break; case OMP_CLAUSE_LASTPRIVATE: + if (OMP_CLAUSE_LASTPRIVATE_LOOP_IV (c) && pass != last) + { + *pc = build_omp_clause (OMP_CLAUSE_LOCATION (c), + OMP_CLAUSE_FIRSTPRIVATE); + OMP_CLAUSE_DECL (*pc) = OMP_CLAUSE_DECL (c); + lang_hooks.decls.omp_finish_clause (*pc, NULL); + pc = &OMP_CLAUSE_CHAIN (*pc); + } *pc = copy_node (c); OMP_CLAUSE_LASTPRIVATE_STMT (*pc) = NULL_TREE; TREE_TYPE (*pc) = unshare_expr (TREE_TYPE (c)); + if (OMP_CLAUSE_LASTPRIVATE_LOOP_IV (c)) + { + if (pass != last) + OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (*pc) = 1; + else + lang_hooks.decls.omp_finish_clause (*pc, NULL); + OMP_CLAUSE_LASTPRIVATE_LOOP_IV (*pc) = 0; + } pc = &OMP_CLAUSE_CHAIN (*pc); break; case OMP_CLAUSE_REDUCTION: diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 5d1b88c76ed..4a6ea0a1b71 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -5139,8 +5139,17 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, x = NULL; do_private: tree nx; - nx = lang_hooks.decls.omp_clause_default_ctor - (c, unshare_expr (new_var), x); + bool copy_ctor; + copy_ctor = false; + nx = unshare_expr (new_var); + if (is_simd + && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE + && OMP_CLAUSE_LASTPRIVATE_LOOP_IV (c)) + copy_ctor = true; + if (copy_ctor) + nx = lang_hooks.decls.omp_clause_copy_ctor (c, nx, x); + else + nx = lang_hooks.decls.omp_clause_default_ctor (c, nx, x); if (is_simd) { tree y = lang_hooks.decls.omp_clause_dtor (c, new_var); @@ -5165,8 +5174,16 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, } if (nx) - x = lang_hooks.decls.omp_clause_default_ctor - (c, unshare_expr (ivar), x); + { + tree iv = unshare_expr (ivar); + if (copy_ctor) + x = lang_hooks.decls.omp_clause_copy_ctor (c, iv, + x); + else + x = lang_hooks.decls.omp_clause_default_ctor (c, + iv, + x); + } else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE__CONDTEMP_) { x = build2 (MODIFY_EXPR, TREE_TYPE (ivar), @@ -6469,9 +6486,9 @@ lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *body_p, x = NULL_TREE; if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE - && OMP_CLAUSE_LASTPRIVATE_TASKLOOP_IV (c)) + && OMP_CLAUSE_LASTPRIVATE_LOOP_IV (c) + && is_taskloop_ctx (ctx)) { - gcc_checking_assert (is_taskloop_ctx (ctx)); tree ovar = maybe_lookup_decl_in_outer_ctx (var, ctx->outer->outer); if (is_global_var (ovar)) diff --git a/gcc/tree.h b/gcc/tree.h index d5fb3b2bd59..ce75b0cdc25 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1517,10 +1517,11 @@ class auto_suppress_location_wrappers #define OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ(NODE) \ (OMP_CLAUSE_CHECK (NODE))->omp_clause.gimple_reduction_init -/* True if a LASTPRIVATE clause is for a C++ class IV on taskloop construct - (thus should be lastprivate on the outer taskloop and firstprivate on - task). */ -#define OMP_CLAUSE_LASTPRIVATE_TASKLOOP_IV(NODE) \ +/* True if a LASTPRIVATE clause is for a C++ class IV on taskloop or + loop construct (thus should be lastprivate on the outer taskloop and + firstprivate on task for the taskloop construct and carefully handled + for loop construct). */ +#define OMP_CLAUSE_LASTPRIVATE_LOOP_IV(NODE) \ TREE_PROTECTED (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_LASTPRIVATE)) /* True if a LASTPRIVATE clause has CONDITIONAL: modifier. */ diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog index 5adcd74a4ec..0331c51c639 100644 --- a/libgomp/ChangeLog +++ b/libgomp/ChangeLog @@ -1,3 +1,9 @@ +2019-08-06 Jakub Jelinek + + * testsuite/libgomp.c++/loop-13.C: New test. + * testsuite/libgomp.c++/loop-14.C: New test. + * testsuite/libgomp.c++/loop-15.C: New test. + 2019-07-31 Jakub Jelinek PR middle-end/91301 diff --git a/libgomp/testsuite/libgomp.c++/loop-13.C b/libgomp/testsuite/libgomp.c++/loop-13.C new file mode 100644 index 00000000000..663212c1f74 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/loop-13.C @@ -0,0 +1,298 @@ +// { dg-do run } + +typedef __PTRDIFF_TYPE__ ptrdiff_t; +extern "C" void abort (); + +template +class I +{ +public: + typedef ptrdiff_t difference_type; + I (); + ~I (); + I (T *); + I (const I &); + T &operator * (); + T *operator -> (); + T &operator [] (const difference_type &) const; + I &operator = (const I &); + I &operator ++ (); + I operator ++ (int); + I &operator -- (); + I operator -- (int); + I &operator += (const difference_type &); + I &operator -= (const difference_type &); + I operator + (const difference_type &) const; + I operator - (const difference_type &) const; + template friend bool operator == (I &, I &); + template friend bool operator == (const I &, const I &); + template friend bool operator < (I &, I &); + template friend bool operator < (const I &, const I &); + template friend bool operator <= (I &, I &); + template friend bool operator <= (const I &, const I &); + template friend bool operator > (I &, I &); + template friend bool operator > (const I &, const I &); + template friend bool operator >= (I &, I &); + template friend bool operator >= (const I &, const I &); + template friend typename I::difference_type operator - (I &, I &); + template friend typename I::difference_type operator - (const I &, const I &); + template friend I operator + (typename I::difference_type , const I &); +private: + T *p; +}; +template I::I () : p (0) {} +template I::~I () {} +template I::I (T *x) : p (x) {} +template I::I (const I &x) : p (x.p) {} +template T &I::operator * () { return *p; } +template T *I::operator -> () { return p; } +template T &I::operator [] (const difference_type &x) const { return p[x]; } +template I &I::operator = (const I &x) { p = x.p; return *this; } +template I &I::operator ++ () { ++p; return *this; } +template I I::operator ++ (int) { return I (p++); } +template I &I::operator -- () { --p; return *this; } +template I I::operator -- (int) { return I (p--); } +template I &I::operator += (const difference_type &x) { p += x; return *this; } +template I &I::operator -= (const difference_type &x) { p -= x; return *this; } +template I I::operator + (const difference_type &x) const { return I (p + x); } +template I I::operator - (const difference_type &x) const { return I (p - x); } +template bool operator == (I &x, I &y) { return x.p == y.p; } +template bool operator == (const I &x, const I &y) { return x.p == y.p; } +template bool operator != (I &x, I &y) { return !(x == y); } +template bool operator != (const I &x, const I &y) { return !(x == y); } +template bool operator < (I &x, I &y) { return x.p < y.p; } +template bool operator < (const I &x, const I &y) { return x.p < y.p; } +template bool operator <= (I &x, I &y) { return x.p <= y.p; } +template bool operator <= (const I &x, const I &y) { return x.p <= y.p; } +template bool operator > (I &x, I &y) { return x.p > y.p; } +template bool operator > (const I &x, const I &y) { return x.p > y.p; } +template bool operator >= (I &x, I &y) { return x.p >= y.p; } +template bool operator >= (const I &x, const I &y) { return x.p >= y.p; } +template typename I::difference_type operator - (I &x, I &y) { return x.p - y.p; } +template typename I::difference_type operator - (const I &x, const I &y) { return x.p - y.p; } +template I operator + (typename I::difference_type x, const I &y) { return I (x + y.p); } + +template +class J +{ +public: + J(const I &x, const I &y) : b (x), e (y) {} + const I &begin (); + const I &end (); +private: + I b, e; +}; + +template const I &J::begin () { return b; } +template const I &J::end () { return e; } + +int results[2000]; + +template +static inline void +baz (I &i) +{ + results[*i]++; +} + +void +f1 (const I &x, const I &y) +{ +#pragma omp parallel loop order(concurrent) + for (I i = x; i <= y; i += 6) + baz (i); +} + +void +f2 (const I &x, const I &y) +{ + I i; +#pragma omp loop private(i) bind(parallel) + for (i = x; i < y - 1; i = 1 - 6 + 7 + i) + baz (i); +} + +template +void +f3 (const I &x, const I &y) +{ +#pragma omp loop bind(thread) order(concurrent) + for (I i = x; i <= y; i = i + 9 - 8) + baz (i); +} + +template +void +f4 (const I &x, const I &y) +{ + I i; +#pragma omp parallel loop lastprivate(i) + for (i = x + 2000 - 64; i > y + 10; --i) + baz (i); +} + +void +f5 (const I &x, const I &y) +{ +#pragma omp loop bind(teams) + for (I i = x + 2000 - 64; i > y + 10; i -= 10) + baz (i); +} + +template +void +f6 (const I &x, const I &y) +{ + I i; +#pragma omp teams loop order(concurrent) + for (i = x + 2000 - 64; i > y + 10; i = i - 12 + 2) + { + I j = i + N; + baz (j); + } +} + +template +void +f7 (I i, const I &x, const I &y) +{ +#pragma omp master +#pragma omp loop + for (i = x - 10; i <= y + 10; i += N) + baz (i); +} + +template +void +f8 (J j) +{ + I i; +#pragma omp parallel loop + for (i = j.begin (); i <= j.end () + N; i += 2) + baz (i); +} + +template +void +f9 (const I &x, const I &y) +{ + I i; +#pragma omp loop bind(teams) private(i) + for (i = x; i <= y; i = i + N) + baz (i); +} + +template +void +f10 (const I &x, const I &y) +{ + I i; +#pragma omp loop bind(thread) private(i) + for (i = x; i > y; i = i + N) + baz (i); +} + +template +void +f11 (const T &x, const T &y) +{ +#pragma omp parallel + { +#pragma omp loop + for (T i = x; i <= y; i += 3) + baz (i); +#pragma omp single + { + T j = y + 3; + baz (j); + } + } +} + +template +void +f12 (const T &x, const T &y) +{ + T i; +#pragma omp loop lastprivate(i) bind(thread) + for (i = x; i > y; --i) + baz (i); +} + +template +struct K +{ + template + static void + f13 (const T &x, const T &y) + { + T i; +#pragma omp teams loop order(concurrent) bind(teams) lastprivate (i) + for (i = x; i <= y + N; i += N) + baz (i); + } +}; + +#define check(expr) \ + for (int i = 0; i < 2000; i++) \ + if (expr) \ + { \ + if (results[i] != 1) \ + abort (); \ + results[i] = 0; \ + } \ + else if (results[i]) \ + abort () + +int +main () +{ + int a[2000]; + long b[2000]; + for (int i = 0; i < 2000; i++) + { + a[i] = i; + b[i] = i; + } + f1 (&a[10], &a[1990]); + check (i >= 10 && i <= 1990 && (i - 10) % 6 == 0); + #pragma omp parallel + f2 (&a[0], &a[1999]); + check (i < 1998 && (i & 1) == 0); + f3 (&a[20], &a[1837]); + check (i >= 20 && i <= 1837); + f4 (&a[0], &a[30]); + check (i > 40 && i <= 2000 - 64); + #pragma omp teams + f5 (&a[0], &a[100]); + check (i >= 116 && i <= 2000 - 64 && (i - 116) % 10 == 0); + f6<-10> (&a[10], &a[110]); + check (i >= 116 && i <= 2000 - 64 && (i - 116) % 10 == 0); + #pragma omp parallel num_threads(2) + f7<6> (I (), &a[12], &a[1800]); + check (i >= 2 && i <= 1808 && (i - 2) % 6 == 0); + f8<121> (J (&a[14], &a[1803])); + check (i >= 14 && i <= 1924 && (i & 1) == 0); + #pragma omp teams + f9 (&a[33], &a[1967]); + check (i >= 33 && i <= 1967 && (i - 33) % 7 == 0); + f10 (&a[1939], &a[17]); + check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0); + f11 > (&a[16], &a[1981]); + check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0); + f12 > (&a[1761], &a[37]); + check (i > 37 && i <= 1761); + K<5>::f13 > (&a[1], &a[1935]); + check (i >= 1 && i <= 1936 && (i - 1) % 5 == 0); + #pragma omp teams + f9 (&b[33], &b[1967]); + check (i >= 33 && i <= 1967 && (i - 33) % 7 == 0); + f10 (&b[1939], &b[17]); + check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0); + f11 > (&b[16], &b[1981]); + check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0); + f12 > (&b[1761], &b[37]); + check (i > 37 && i <= 1761); + K<5>::f13 > (&b[1], &b[1935]); + check (i >= 1 && i <= 1936 && (i - 1) % 5 == 0); +} diff --git a/libgomp/testsuite/libgomp.c++/loop-14.C b/libgomp/testsuite/libgomp.c++/loop-14.C new file mode 100644 index 00000000000..191ab681b3c --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/loop-14.C @@ -0,0 +1,301 @@ +// { dg-do run } + +typedef __PTRDIFF_TYPE__ ptrdiff_t; +extern "C" void abort (); + +template +class I +{ +public: + typedef ptrdiff_t difference_type; + I (); + ~I (); + I (T *); + I (const I &); + T &operator * (); + T *operator -> (); + T &operator [] (const difference_type &) const; + I &operator = (const I &); + I &operator ++ (); + I operator ++ (int); + I &operator -- (); + I operator -- (int); + I &operator += (const difference_type &); + I &operator -= (const difference_type &); + I operator + (const difference_type &) const; + I operator - (const difference_type &) const; + template friend bool operator == (I &, I &); + template friend bool operator == (const I &, const I &); + template friend bool operator < (I &, I &); + template friend bool operator < (const I &, const I &); + template friend bool operator <= (I &, I &); + template friend bool operator <= (const I &, const I &); + template friend bool operator > (I &, I &); + template friend bool operator > (const I &, const I &); + template friend bool operator >= (I &, I &); + template friend bool operator >= (const I &, const I &); + template friend typename I::difference_type operator - (I &, I &); + template friend typename I::difference_type operator - (const I &, const I &); + template friend I operator + (typename I::difference_type , const I &); +private: + T *p; +}; +template I::I () : p (0) {} +template I::~I () { p = (T *) 0; } +template I::I (T *x) : p (x) {} +template I::I (const I &x) : p (x.p) {} +template T &I::operator * () { return *p; } +template T *I::operator -> () { return p; } +template T &I::operator [] (const difference_type &x) const { return p[x]; } +template I &I::operator = (const I &x) { p = x.p; return *this; } +template I &I::operator ++ () { ++p; return *this; } +template I I::operator ++ (int) { return I (p++); } +template I &I::operator -- () { --p; return *this; } +template I I::operator -- (int) { return I (p--); } +template I &I::operator += (const difference_type &x) { p += x; return *this; } +template I &I::operator -= (const difference_type &x) { p -= x; return *this; } +template I I::operator + (const difference_type &x) const { return I (p + x); } +template I I::operator - (const difference_type &x) const { return I (p - x); } +template bool operator == (I &x, I &y) { return x.p == y.p; } +template bool operator == (const I &x, const I &y) { return x.p == y.p; } +template bool operator != (I &x, I &y) { return !(x == y); } +template bool operator != (const I &x, const I &y) { return !(x == y); } +template bool operator < (I &x, I &y) { return x.p < y.p; } +template bool operator < (const I &x, const I &y) { return x.p < y.p; } +template bool operator <= (I &x, I &y) { return x.p <= y.p; } +template bool operator <= (const I &x, const I &y) { return x.p <= y.p; } +template bool operator > (I &x, I &y) { return x.p > y.p; } +template bool operator > (const I &x, const I &y) { return x.p > y.p; } +template bool operator >= (I &x, I &y) { return x.p >= y.p; } +template bool operator >= (const I &x, const I &y) { return x.p >= y.p; } +template typename I::difference_type operator - (I &x, I &y) { return x.p - y.p; } +template typename I::difference_type operator - (const I &x, const I &y) { return x.p - y.p; } +template I operator + (typename I::difference_type x, const I &y) { return I (x + y.p); } + +template +class J +{ +public: + J(const I &x, const I &y) : b (x), e (y) {} + const I &begin (); + const I &end (); +private: + I b, e; +}; + +template const I &J::begin () { return b; } +template const I &J::end () { return e; } + +int results[2000]; + +template +static inline void +baz (I &i) +{ + results[*i]++; +} + +I +f1 (const I &x, const I &y) +{ + I i; +#pragma omp parallel shared (i) + { + #pragma omp loop lastprivate (i) order(concurrent) + for (i = x; i < y - 1; ++i) + baz (i); + #pragma omp single + i += 3; + } + return I (i); +} + +I +f2 (const I &x, const I &y) +{ + I i; +#pragma omp parallel loop bind(parallel) + for (i = x; i < y - 1; i = 1 - 6 + 7 + i) + baz (i); + return I (i); +} + +template +I +f3 (const I &x, const I &y) +{ + I i; +#pragma omp teams + #pragma omp loop order(concurrent) + for (i = x + 1000 - 64; i <= y - 10; i++) + baz (i); + return i; +} + +template +I +f4 (const I &x, const I &y) +{ + I i; +#pragma omp teams loop lastprivate (i) + for (i = x + 2000 - 64; i > y + 10; --i) + baz (i); + return I (i); +} + +template +I +f5 (const I &x, const I &y) +{ + I i; +#pragma omp loop lastprivate (i) bind(thread) + for (i = x; i > y + T (6); i--) + baz (i); + return i; +} + +template +I +f6 (const I &x, const I &y) +{ + I i; +#pragma omp loop bind(thread) + for (i = x - T (7); i > y; i -= T (2)) + baz (i); + return I (i); +} + +template +I +f7 (I i, const I &x, const I &y) +{ +#pragma omp parallel for lastprivate (i) + for (i = x - 10; i <= y + 10; i += N) + baz (i); + return I (i); +} + +template +I +f8 (J j) +{ + I i; +#pragma omp parallel shared (i) + #pragma omp loop lastprivate (i) + for (i = j.begin (); i <= j.end () + N; i += 2) + baz (i); + return i; +} + +I i9; + +template +I & +f9 (J j) +{ +#pragma omp loop bind(parallel) + for (i9 = j.begin () + N; i9 <= j.end () - N; i9 = i9 - N) + baz (i9); + return i9; +} + +template +I +f10 (const I &x, const I &y) +{ + I i; +#pragma omp parallel loop lastprivate (i) + for (i = x; i > y; i = i + N) + baz (i); + return i; +} + +template +T +f11 (T i, const T &x, const T &y) +{ + #pragma omp loop bind(thread) + for (i = x + U (2); i <= y + U (1); i = U (2) + U (3) + i) + baz (i); + return T (i); +} + +template +T +f12 (const T &x, const T &y) +{ + T i; +#pragma omp teams loop + for (i = x; i > y; --i) + baz (i); + return i; +} + +#define check(expr) \ + for (int i = 0; i < 2000; i++) \ + if (expr) \ + { \ + if (results[i] != 1) \ + abort (); \ + results[i] = 0; \ + } \ + else if (results[i]) \ + abort () + +int +main () +{ + int a[2000]; + long b[2000]; + for (int i = 0; i < 2000; i++) + { + a[i] = i; + b[i] = i; + } + if (*f1 (&a[10], &a[1873]) != 1875) + abort (); + check (i >= 10 && i < 1872); + if (*f2 (&a[0], &a[1998]) != 1998) + abort (); + check (i < 1997 && (i & 1) == 0); + if (*f3 (&a[10], &a[1971]) != 1962) + abort (); + check (i >= 946 && i <= 1961); + if (*f4 (&a[0], &a[30]) != 40) + abort (); + check (i > 40 && i <= 2000 - 64); + if (*f5 (&a[1931], &a[17]) != 23) + abort (); + check (i > 23 && i <= 1931); + if (*f6 (&a[1931], &a[17]) != 16) + abort (); + check (i > 17 && i <= 1924 && (i & 1) == 0); + if (*f7<6> (I (), &a[12], &a[1800]) != 1814) + abort (); + check (i >= 2 && i <= 1808 && (i - 2) % 6 == 0); + if (*f8<121> (J (&a[14], &a[1803])) != 1926) + abort (); + check (i >= 14 && i <= 1924 && (i & 1) == 0); + #pragma omp parallel + if (*f9<-3L> (J (&a[27], &a[1761])) != 1767) + abort (); + check (i >= 24 && i <= 1764 && (i % 3) == 0); + if (*f10 (&a[1939], &a[17]) != 14) + abort (); + check (i >= 21 && i <= 1939 && i % 7 == 0); + if (*f11, short> (I (), &a[71], &a[1941]) != 1943) + abort (); + check (i >= 73 && i <= 1938 && (i - 73) % 5 == 0); + if (*f12 > (&a[1761], &a[37]) != 37) + abort (); + check (i > 37 && i <= 1761); + if (*f10 (&b[1939], &b[17]) != 14) + abort (); + check (i >= 21 && i <= 1939 && i % 7 == 0); + if (*f11, short> (I (), &b[71], &b[1941]) != 1943) + abort (); + check (i >= 73 && i <= 1938 && (i - 73) % 5 == 0); + if (*f12 > (&b[1761], &b[37]) != 37) + abort (); + check (i > 37 && i <= 1761); +} diff --git a/libgomp/testsuite/libgomp.c++/loop-15.C b/libgomp/testsuite/libgomp.c++/loop-15.C new file mode 100644 index 00000000000..b523b9bd2f9 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/loop-15.C @@ -0,0 +1,417 @@ +// { dg-do run } +// { dg-additional-options "-std=c++17" } + +typedef __PTRDIFF_TYPE__ ptrdiff_t; +extern "C" void abort (); + +namespace std { + template struct tuple_size; + template struct tuple_element; +} + +template +class I +{ +public: + typedef ptrdiff_t difference_type; + I (); + ~I (); + I (T *); + I (const I &); + T &operator * (); + T *operator -> (); + T &operator [] (const difference_type &) const; + I &operator = (const I &); + I &operator ++ (); + I operator ++ (int); + I &operator -- (); + I operator -- (int); + I &operator += (const difference_type &); + I &operator -= (const difference_type &); + I operator + (const difference_type &) const; + I operator - (const difference_type &) const; + template friend bool operator == (I &, I &); + template friend bool operator == (const I &, const I &); + template friend bool operator < (I &, I &); + template friend bool operator < (const I &, const I &); + template friend bool operator <= (I &, I &); + template friend bool operator <= (const I &, const I &); + template friend bool operator > (I &, I &); + template friend bool operator > (const I &, const I &); + template friend bool operator >= (I &, I &); + template friend bool operator >= (const I &, const I &); + template friend typename I::difference_type operator - (I &, I &); + template friend typename I::difference_type operator - (const I &, const I &); + template friend I operator + (typename I::difference_type , const I &); +private: + T *p; +}; +template I::I () : p (0) {} +template I::~I () {} +template I::I (T *x) : p (x) {} +template I::I (const I &x) : p (x.p) {} +template T &I::operator * () { return *p; } +template T *I::operator -> () { return p; } +template T &I::operator [] (const difference_type &x) const { return p[x]; } +template I &I::operator = (const I &x) { p = x.p; return *this; } +template I &I::operator ++ () { ++p; return *this; } +template I I::operator ++ (int) { return I (p++); } +template I &I::operator -- () { --p; return *this; } +template I I::operator -- (int) { return I (p--); } +template I &I::operator += (const difference_type &x) { p += x; return *this; } +template I &I::operator -= (const difference_type &x) { p -= x; return *this; } +template I I::operator + (const difference_type &x) const { return I (p + x); } +template I I::operator - (const difference_type &x) const { return I (p - x); } +template bool operator == (I &x, I &y) { return x.p == y.p; } +template bool operator == (const I &x, const I &y) { return x.p == y.p; } +template bool operator != (I &x, I &y) { return !(x == y); } +template bool operator != (const I &x, const I &y) { return !(x == y); } +template bool operator < (I &x, I &y) { return x.p < y.p; } +template bool operator < (const I &x, const I &y) { return x.p < y.p; } +template bool operator <= (I &x, I &y) { return x.p <= y.p; } +template bool operator <= (const I &x, const I &y) { return x.p <= y.p; } +template bool operator > (I &x, I &y) { return x.p > y.p; } +template bool operator > (const I &x, const I &y) { return x.p > y.p; } +template bool operator >= (I &x, I &y) { return x.p >= y.p; } +template bool operator >= (const I &x, const I &y) { return x.p >= y.p; } +template typename I::difference_type operator - (I &x, I &y) { return x.p - y.p; } +template typename I::difference_type operator - (const I &x, const I &y) { return x.p - y.p; } +template I operator + (typename I::difference_type x, const I &y) { return I (x + y.p); } + +template +class J +{ +public: + J(const I &x, const I &y) : b (x), e (y) {} + const I &begin (); + const I &end (); +private: + I b, e; +}; + +template const I &J::begin () { return b; } +template const I &J::end () { return e; } + +template +class K +{ +public: + K (); + ~K (); + template T &get () { if (N == 0) return c; else if (N == 1) return b; return a; } + T a, b, c; +}; + +template K::K () : a {}, b {}, c {} {} +template K::~K () {} +template struct std::tuple_size> { static constexpr int value = 3; }; +template struct std::tuple_element> { using type = T; }; + +template +class L +{ +public: + L (); + ~L (); + T a, b, c; +}; + +template L::L () : a {}, b {}, c {} {} +template L::~L () {} + +int a[2000]; +long b[40]; +short c[50]; +int d[1024]; +K e[1089]; +L f[1093]; +int results[2000]; + +template +static inline void +baz (I &i) +{ + results[*i]++; +} + +static inline void +baz (int i) +{ + results[i]++; +} + +void +f1 () +{ +#pragma omp parallel loop shared(a) default(none) + for (auto i : a) + baz (i); +} + +void +f2 () +{ +#pragma omp loop order(concurrent) bind(parallel) + for (auto &i : a) + if (&i != &a[i]) + abort (); + else + baz (i); +} + +void +f3 () +{ +#pragma omp teams loop collapse(3) default(none) shared(b, c) + for (auto &i : b) + for (int j = 9; j < 10; j++) + for (auto k : c) + if (&i != &b[i] || i < 0 || i >= 40 || j != 9 || k < 0 || k >= 50) + abort (); + else + baz (i * 50 + k); +} + +void +f4 (J j) +{ +#pragma omp loop bind(teams) + for (auto &i : j) + if (&i != &a[i]) + abort (); + else + baz (i); +} + +void +f5 () +{ +#pragma omp loop bind(thread) + for (auto i : d) + results[i % 1024] += 2 * ((unsigned) i >> 10) + 1; +} + +void +f6 (J> j) +{ +#pragma omp loop bind(parallel) + for (auto & [k, l, m] : j) + if (&k != &e[m].c || &l != &e[m].b || &m != &e[m].a || k != m * 3 || l != m * 2) + abort (); + else + baz (m); +} + +void +f7 (J> j) +{ +#pragma omp parallel loop default(none) shared(j, f) + for (auto & [k, l, m] : j) + if (&k != &f[k].a || &l != &f[k].b || &m != &f[k].c || l != k * 4 || m != k * 5) + abort (); + else + baz (k); +} + +void +f8 (J> j) +{ +#pragma omp parallel loop default(none) shared(j) + for (auto [k, l, m] : j) + if (k != m * 3 || l != m * 2) + abort (); + else + baz (m); +} + +void +f9 (J> j) +{ +#pragma omp teams loop default(none) shared(j) + for (auto [k, l, m] : j) + if (l != k * 4 || m != k * 5) + abort (); + else + baz (k); +} + +template +void +f10 () +{ +#pragma omp loop bind(teams) + for (auto i : a) + baz (i); +} + +template +void +f11 () +{ +#pragma omp loop bind(thread) + for (auto &i : a) + if (&i != &a[i]) + abort (); + else + baz (i); +} + +template +void +f12 () +{ +#pragma omp parallel loop collapse(3) default(none) shared(a, b, c) bind(parallel) + for (auto &i : b) + for (I j = I (&a[9]); j < I (&a[10]); j++) + for (auto k : c) + if (&i != &b[i] || i < 0 || i >= 40 || *j != 9 || k < 0 || k >= 50) + abort (); + else + baz (i * 50 + k); +} + +template +void +f13 (J j) +{ +#pragma omp loop bind(thread) + for (auto &i : j) + if (&i != &a[i]) + abort (); + else + baz (i); +} + +template +void +f14 () +{ +#pragma omp parallel loop default(none) shared(d, results) + for (auto i : d) + results[i % N] += 2 * ((unsigned) i >> 10) + 1; +} + +template +void +f15 (J> j) +{ +#pragma omp parallel loop default(none) shared(j, e) bind(parallel) + for (auto & [k, l, m] : j) + if (&k != &e[m].c || &l != &e[m].b || &m != &e[m].a || k != m * 3 || l != m * 2) + abort (); + else + baz (m); +} + +template +void +f16 (J> j) +{ +#pragma omp loop bind(parallel) + for (auto & [k, l, m] : j) + if (&k != &f[k].a || &l != &f[k].b || &m != &f[k].c || l != k * 4 || m != k * 5) + abort (); + else + baz (k); +} + +template +void +f17 (J> j) +{ +#pragma omp parallel loop default(none) shared(j) + for (auto [k, l, m] : j) + if (k != m * 3 || l != m * 2) + abort (); + else + baz (m); +} + +template +void +f18 (J> j) +{ +#pragma omp teams loop default(none) shared(j) + for (auto [k, l, m] : j) + if (l != k * 4 || m != k * 5) + abort (); + else + baz (k); +} + +#define check(expr) \ + for (int i = 0; i < 2000; i++) \ + if (expr) \ + { \ + if (results[i] != 1) \ + abort (); \ + results[i] = 0; \ + } \ + else if (results[i]) \ + abort () + +int +main () +{ + for (int i = 0; i < 2000; i++) + a[i] = i; + for (int i = 0; i < 40; i++) + b[i] = i; + for (int i = 0; i < 50; i++) + c[i] = i; + for (int i = 0; i < 1024; i++) + d[i] = i; + for (int i = 0; i < 1089; i++) + { + e[i].a = i; + e[i].b = 2 * i; + e[i].c = 3 * i; + } + for (int i = 0; i < 1093; i++) + { + f[i].a = i; + f[i].b = 4 * i; + f[i].c = 5 * i; + } + f1 (); + check (1); + #pragma omp parallel + f2 (); + check (1); + f3 (); + check (1); + #pragma omp teams + f4 (J (&a[14], &a[1803])); + check (i >= 14 && i < 1803); + f5 (); + check (i >= 0 && i < 1024); + #pragma omp parallel + f6 (J> (&e[19], &e[1029])); + check (i >= 19 && i < 1029); + f7 (J> (&f[15], &f[1091])); + check (i >= 15 && i < 1091); + f8 (J> (&e[27], &e[1037])); + check (i >= 27 && i < 1037); + f9 (J> (&f[1], &f[1012])); + check (i >= 1 && i < 1012); + #pragma omp teams + f10 <0> (); + check (1); + f11 <1> (); + check (1); + f12 <2> (); + check (1); + f13 (J (&a[24], &a[1703])); + check (i >= 24 && i < 1703); + f14 <1024> (); + check (i >= 0 && i < 1024); + f15 (J> (&e[39], &e[929])); + check (i >= 39 && i < 929); + #pragma omp parallel + f16 (J> (&f[17], &f[1071])); + check (i >= 17 && i < 1071); + f17 <3> (J> (&e[7], &e[1017])); + check (i >= 7 && i < 1017); + f18 <5> (J> (&f[121], &f[1010])); + check (i >= 121 && i < 1010); +} -- 2.30.2