From: Jakub Jelinek Date: Tue, 10 Jul 2018 07:12:37 +0000 (+0200) Subject: re PR c++/86443 (ICEs on #pragma omp distribute parallel for with class iterators) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0b27c3eda934bfc946d64fb72203001c5bee46a1;p=gcc.git re PR c++/86443 (ICEs on #pragma omp distribute parallel for with class iterators) PR c++/86443 * gimplify.c (find_combined_omp_for): Add DATA argument, in addition to finding the inner OMP_FOR/OMP_SIMD stmt find non-trivial wrappers, BLOCKs with BLOCK_VARs, OMP_PARALLEL in between, OMP_FOR in between. (gimplify_omp_for): For composite loops, move outer OMP_{DISTRIBUTE,TASKLOOP,FOR,PARALLEL} right around innermost OMP_FOR/OMP_SIMD if there are any non-trivial wrappers. For class iterators add any needed clauses. Allow OMP_FOR_ORIG_DECLS to contain TREE_LIST for both the original class iterator and the "last" helper var. Gimplify OMP_FOR_PRE_BODY before the outermost composite loop, remember has_decl_expr from outer composite loops for the innermost OMP_SIMD in TREE_PRIVATE bit on OMP_FOR_INIT. gcc/c-family/ * c-omp.c (c_omp_check_loop_iv_r, c_omp_check_loop_iv): Allow declv to contain TREE_LIST for both the original class iterator and the "last" helper var. gcc/cp/ * semantics.c (handle_omp_for_class_iterator): Remove lastp argument, instead of setting *lastp turn orig_declv elt into a TREE_LIST. (finish_omp_for): Adjust handle_omp_for_class_iterator caller. * pt.c (tsubst_omp_for_iterator): Allow OMP_FOR_ORIG_DECLS to contain TREE_LIST for both the original class iterator and the "last" helper var. libgomp/ * testsuite/libgomp.c++/for-15.C: New test. From-SVN: r262534 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index dda22d8e180..3230cf3aa82 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2018-07-10 Jakub Jelinek + + PR c++/86443 + * gimplify.c (find_combined_omp_for): Add DATA argument, in addition + to finding the inner OMP_FOR/OMP_SIMD stmt find non-trivial wrappers, + BLOCKs with BLOCK_VARs, OMP_PARALLEL in between, OMP_FOR in between. + (gimplify_omp_for): For composite loops, move outer + OMP_{DISTRIBUTE,TASKLOOP,FOR,PARALLEL} right around innermost + OMP_FOR/OMP_SIMD if there are any non-trivial wrappers. For class + iterators add any needed clauses. Allow OMP_FOR_ORIG_DECLS to contain + TREE_LIST for both the original class iterator and the "last" helper + var. Gimplify OMP_FOR_PRE_BODY before the outermost composite + loop, remember has_decl_expr from outer composite loops for the + innermost OMP_SIMD in TREE_PRIVATE bit on OMP_FOR_INIT. + 2018-07-09 Martin Sebor PR middle-end/77357 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index bf4e7e9bd89..a459f061326 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,10 @@ +2018-07-10 Jakub Jelinek + + PR c++/86443 + * c-omp.c (c_omp_check_loop_iv_r, c_omp_check_loop_iv): Allow declv + to contain TREE_LIST for both the original class iterator and the + "last" helper var. + 2018-07-07 Eric Botcazou * c-ada-spec.c (to_ada_name): Remove index parameter. diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index d8695f517af..89849379ca7 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -827,7 +827,9 @@ c_omp_check_loop_iv_r (tree *tp, int *walk_subtrees, void *data) { int i; for (i = 0; i < TREE_VEC_LENGTH (d->declv); i++) - if (*tp == TREE_VEC_ELT (d->declv, i)) + if (*tp == TREE_VEC_ELT (d->declv, i) + || (TREE_CODE (TREE_VEC_ELT (d->declv, i)) == TREE_LIST + && *tp == TREE_PURPOSE (TREE_VEC_ELT (d->declv, i)))) { location_t loc = d->expr_loc; if (loc == UNKNOWN_LOCATION) @@ -894,7 +896,9 @@ c_omp_check_loop_iv (tree stmt, tree declv, walk_tree_lh lh) expression then involves the subtraction and always refers to the original value. The C++ FE needs to warn on those earlier. */ - if (decl == TREE_VEC_ELT (declv, i)) + if (decl == TREE_VEC_ELT (declv, i) + || (TREE_CODE (TREE_VEC_ELT (declv, i)) == TREE_LIST + && decl == TREE_PURPOSE (TREE_VEC_ELT (declv, i)))) { data.expr_loc = EXPR_LOCATION (cond); data.kind = 1; diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 82cb481ff77..86d4a349905 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,13 @@ +2018-07-10 Jakub Jelinek + + PR c++/86443 + * semantics.c (handle_omp_for_class_iterator): Remove lastp argument, + instead of setting *lastp turn orig_declv elt into a TREE_LIST. + (finish_omp_for): Adjust handle_omp_for_class_iterator caller. + * pt.c (tsubst_omp_for_iterator): Allow OMP_FOR_ORIG_DECLS to contain + TREE_LIST for both the original class iterator and the "last" helper + var. + 2018-07-09 Paolo Carlini * decl.c (grokdeclarator): Use rich_location::add_range in three diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 3780f3492aa..eae9e14d37d 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -16267,7 +16267,12 @@ tsubst_omp_for_iterator (tree t, int i, tree declv, tree orig_declv, if (orig_declv && OMP_FOR_ORIG_DECLS (t)) { tree o = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (t), i); - TREE_VEC_ELT (orig_declv, i) = RECUR (o); + if (TREE_CODE (o) == TREE_LIST) + TREE_VEC_ELT (orig_declv, i) + = tree_cons (RECUR (TREE_PURPOSE (o)), + RECUR (TREE_VALUE (o)), NULL_TREE); + else + TREE_VEC_ELT (orig_declv, i) = RECUR (o); } decl = TREE_OPERAND (init, 0); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index c779137da45..ef73d07161f 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -7679,7 +7679,7 @@ static bool handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code, tree declv, tree orig_declv, tree initv, tree condv, tree incrv, tree *body, - tree *pre_body, tree &clauses, tree *lastp, + tree *pre_body, tree &clauses, int collapse, int ordered) { tree diff, iter_init, iter_incr = NULL, last; @@ -7983,7 +7983,8 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code, TREE_VEC_ELT (initv, i) = init; TREE_VEC_ELT (condv, i) = cond; TREE_VEC_ELT (incrv, i) = incr; - *lastp = last; + TREE_VEC_ELT (orig_declv, i) + = tree_cons (TREE_VEC_ELT (orig_declv, i), last, NULL_TREE); return false; } @@ -8002,7 +8003,6 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv, { tree omp_for = NULL, orig_incr = NULL; tree decl = NULL, init, cond, incr; - tree last = NULL_TREE; location_t elocus; int i; int collapse = 1; @@ -8169,7 +8169,7 @@ finish_omp_for (location_t locus, enum tree_code code, tree declv, } if (handle_omp_for_class_iterator (i, locus, code, declv, orig_declv, initv, condv, incrv, &body, - &pre_body, clauses, &last, + &pre_body, clauses, collapse, ordered)) return NULL; continue; diff --git a/gcc/gimplify.c b/gcc/gimplify.c index c86ad1ad962..6b76d17dbaf 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -9532,24 +9532,53 @@ gimplify_omp_task (tree *expr_p, gimple_seq *pre_p) } /* Helper function of gimplify_omp_for, find OMP_FOR resp. OMP_SIMD - with non-NULL OMP_FOR_INIT. */ + with non-NULL OMP_FOR_INIT. Also, fill in pdata array, + pdata[0] non-NULL if there is anything non-trivial in between, pdata[1] + is address of OMP_PARALLEL in between if any, pdata[2] is address of + OMP_FOR in between if any and pdata[3] is address of the inner + OMP_FOR/OMP_SIMD. */ static tree -find_combined_omp_for (tree *tp, int *walk_subtrees, void *) +find_combined_omp_for (tree *tp, int *walk_subtrees, void *data) { + tree **pdata = (tree **) data; *walk_subtrees = 0; switch (TREE_CODE (*tp)) { case OMP_FOR: + if (OMP_FOR_INIT (*tp) != NULL_TREE) + { + pdata[3] = tp; + return *tp; + } + pdata[2] = tp; *walk_subtrees = 1; - /* FALLTHRU */ + break; case OMP_SIMD: if (OMP_FOR_INIT (*tp) != NULL_TREE) - return *tp; + { + pdata[3] = tp; + return *tp; + } break; case BIND_EXPR: + if (BIND_EXPR_VARS (*tp) + || (BIND_EXPR_BLOCK (*tp) + && BLOCK_VARS (BIND_EXPR_BLOCK (*tp)))) + pdata[0] = tp; + *walk_subtrees = 1; + break; case STATEMENT_LIST: + if (!tsi_one_before_end_p (tsi_start (*tp))) + pdata[0] = tp; + *walk_subtrees = 1; + break; + case TRY_FINALLY_EXPR: + pdata[0] = tp; + *walk_subtrees = 1; + break; case OMP_PARALLEL: + pdata[1] = tp; *walk_subtrees = 1; break; default: @@ -9574,6 +9603,115 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) orig_for_stmt = for_stmt = *expr_p; + if (OMP_FOR_INIT (for_stmt) == NULL_TREE) + { + tree *data[4] = { NULL, NULL, NULL, NULL }; + gcc_assert (TREE_CODE (for_stmt) != OACC_LOOP); + inner_for_stmt = walk_tree (&OMP_FOR_BODY (for_stmt), + find_combined_omp_for, data, NULL); + if (inner_for_stmt == NULL_TREE) + { + gcc_assert (seen_error ()); + *expr_p = NULL_TREE; + return GS_ERROR; + } + if (data[2] && OMP_FOR_PRE_BODY (*data[2])) + { + append_to_statement_list_force (OMP_FOR_PRE_BODY (*data[2]), + &OMP_FOR_PRE_BODY (for_stmt)); + OMP_FOR_PRE_BODY (*data[2]) = NULL_TREE; + } + if (OMP_FOR_PRE_BODY (inner_for_stmt)) + { + append_to_statement_list_force (OMP_FOR_PRE_BODY (inner_for_stmt), + &OMP_FOR_PRE_BODY (for_stmt)); + OMP_FOR_PRE_BODY (inner_for_stmt) = NULL_TREE; + } + + if (data[0]) + { + /* We have some statements or variable declarations in between + the composite construct directives. Move them around the + inner_for_stmt. */ + data[0] = expr_p; + for (i = 0; i < 3; i++) + if (data[i]) + { + tree t = *data[i]; + if (i < 2 && data[i + 1] == &OMP_BODY (t)) + data[i + 1] = data[i]; + *data[i] = OMP_BODY (t); + tree body = build3 (BIND_EXPR, void_type_node, NULL_TREE, + NULL_TREE, make_node (BLOCK)); + OMP_BODY (t) = body; + append_to_statement_list_force (inner_for_stmt, + &BIND_EXPR_BODY (body)); + *data[3] = t; + data[3] = tsi_stmt_ptr (tsi_start (BIND_EXPR_BODY (body))); + gcc_assert (*data[3] == inner_for_stmt); + } + return GS_OK; + } + + for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (inner_for_stmt)); i++) + if (OMP_FOR_ORIG_DECLS (inner_for_stmt) + && TREE_CODE (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (inner_for_stmt), + i)) == TREE_LIST) + { + 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. */ + gcc_assert (TREE_CODE (inner_for_stmt) == OMP_FOR + && TREE_CODE (for_stmt) == OMP_DISTRIBUTE + && data[1]); + tree orig_decl = TREE_PURPOSE (orig); + tree last = TREE_VALUE (orig); + tree *pc; + for (pc = &OMP_FOR_CLAUSES (inner_for_stmt); + *pc; pc = &OMP_CLAUSE_CHAIN (*pc)) + if ((OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_PRIVATE + || OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_LASTPRIVATE) + && OMP_CLAUSE_DECL (*pc) == orig_decl) + break; + if (*pc == NULL_TREE) + ; + else if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_PRIVATE) + { + /* private clause will appear only on inner_for_stmt. + Change it into firstprivate, and add private clause + on for_stmt. */ + tree c = copy_node (*pc); + OMP_CLAUSE_CHAIN (c) = OMP_FOR_CLAUSES (for_stmt); + OMP_FOR_CLAUSES (for_stmt) = c; + OMP_CLAUSE_CODE (*pc) = OMP_CLAUSE_FIRSTPRIVATE; + lang_hooks.decls.omp_finish_clause (*pc, pre_p); + } + else + { + /* lastprivate clause will appear on both inner_for_stmt + and for_stmt. Add firstprivate clause to + inner_for_stmt. */ + tree c = build_omp_clause (OMP_CLAUSE_LOCATION (*pc), + OMP_CLAUSE_FIRSTPRIVATE); + OMP_CLAUSE_DECL (c) = OMP_CLAUSE_DECL (*pc); + OMP_CLAUSE_CHAIN (c) = *pc; + *pc = c; + lang_hooks.decls.omp_finish_clause (*pc, pre_p); + } + tree c = build_omp_clause (UNKNOWN_LOCATION, + OMP_CLAUSE_FIRSTPRIVATE); + OMP_CLAUSE_DECL (c) = last; + OMP_CLAUSE_CHAIN (c) = OMP_PARALLEL_CLAUSES (*data[1]); + OMP_PARALLEL_CLAUSES (*data[1]) = c; + c = build_omp_clause (UNKNOWN_LOCATION, + *pc ? OMP_CLAUSE_SHARED + : OMP_CLAUSE_FIRSTPRIVATE); + OMP_CLAUSE_DECL (c) = orig_decl; + OMP_CLAUSE_CHAIN (c) = OMP_PARALLEL_CLAUSES (*data[1]); + OMP_PARALLEL_CLAUSES (*data[1]) = c; + } + } + switch (TREE_CODE (for_stmt)) { case OMP_FOR: @@ -9611,19 +9749,6 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) } } - if (OMP_FOR_INIT (for_stmt) == NULL_TREE) - { - gcc_assert (TREE_CODE (for_stmt) != OACC_LOOP); - inner_for_stmt = walk_tree (&OMP_FOR_BODY (for_stmt), - find_combined_omp_for, NULL, NULL); - if (inner_for_stmt == NULL_TREE) - { - gcc_assert (seen_error ()); - *expr_p = NULL_TREE; - return GS_ERROR; - } - } - if (TREE_CODE (for_stmt) != OMP_TASKLOOP) gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p, ort, TREE_CODE (for_stmt)); @@ -9633,7 +9758,9 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) /* Handle OMP_FOR_INIT. */ for_pre_body = NULL; - if (ort == ORT_SIMD && OMP_FOR_PRE_BODY (for_stmt)) + if ((ort == ORT_SIMD + || (inner_for_stmt && TREE_CODE (inner_for_stmt) == OMP_SIMD)) + && OMP_FOR_PRE_BODY (for_stmt)) { has_decl_expr = BITMAP_ALLOC (NULL); if (TREE_CODE (OMP_FOR_PRE_BODY (for_stmt)) == DECL_EXPR @@ -9774,8 +9901,12 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) if (is_doacross) { if (TREE_CODE (for_stmt) == OMP_FOR && OMP_FOR_ORIG_DECLS (for_stmt)) - gimplify_omp_ctxp->loop_iter_var.quick_push - (TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt), i)); + { + tree orig_decl = TREE_VEC_ELT (OMP_FOR_ORIG_DECLS (for_stmt), i); + if (TREE_CODE (orig_decl) == TREE_LIST) + orig_decl = TREE_PURPOSE (orig_decl); + gimplify_omp_ctxp->loop_iter_var.quick_push (orig_decl); + } else gimplify_omp_ctxp->loop_iter_var.quick_push (decl); gimplify_omp_ctxp->loop_iter_var.quick_push (decl); @@ -9785,7 +9916,12 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) tree c = NULL_TREE; tree c2 = NULL_TREE; if (orig_for_stmt != for_stmt) - /* Do this only on innermost construct for combined ones. */; + { + /* Preserve this information until we gimplify the inner simd. */ + if (has_decl_expr + && bitmap_bit_p (has_decl_expr, DECL_UID (decl))) + TREE_PRIVATE (t) = 1; + } else if (ort == ORT_SIMD) { splay_tree_node n = splay_tree_lookup (gimplify_omp_ctxp->variables, @@ -9800,8 +9936,9 @@ 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; unsigned int flags = GOVD_LINEAR | GOVD_EXPLICIT | GOVD_SEEN; - if (has_decl_expr - && bitmap_bit_p (has_decl_expr, DECL_UID (decl))) + if ((has_decl_expr + && bitmap_bit_p (has_decl_expr, DECL_UID (decl))) + || TREE_PRIVATE (t)) { OMP_CLAUSE_LINEAR_NO_COPYOUT (c) = 1; flags |= GOVD_LINEAR_LASTPRIVATE_NO_OUTER; @@ -9923,6 +10060,8 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) bool lastprivate = (!has_decl_expr || !bitmap_bit_p (has_decl_expr, DECL_UID (decl))); + if (TREE_PRIVATE (t)) + lastprivate = false; struct gimplify_omp_ctx *outer = gimplify_omp_ctxp->outer_context; if (outer && lastprivate) diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog index ef0cdd06422..1423598d189 100644 --- a/libgomp/ChangeLog +++ b/libgomp/ChangeLog @@ -1,3 +1,8 @@ +2018-07-10 Jakub Jelinek + + PR c++/86443 + * testsuite/libgomp.c++/for-15.C: New test. + 2018-06-26 Jakub Jelinek PR c++/86291 diff --git a/libgomp/testsuite/libgomp.c++/for-15.C b/libgomp/testsuite/libgomp.c++/for-15.C new file mode 100644 index 00000000000..5e922acc0fa --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/for-15.C @@ -0,0 +1,232 @@ +// PR c++/86443 +// { dg-do run } +// { dg-additional-options "-std=c++17" } + +typedef __PTRDIFF_TYPE__ ptrdiff_t; +extern "C" void abort (); + +#pragma omp declare target +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 a[2000]; +int results[2000]; + +template +void +baz (I &i) +{ + if (*i < 0 || *i >= 2000) + abort (); + results[*i]++; +} + +void +baz (int i) +{ + if (i < 0 || i >= 2000) + abort (); + results[i]++; +} + +void +qux (I &i) +{ + if (*i != 1931) + abort (); +} + +void +f1 (J j) +{ +#pragma omp distribute parallel for default(none) + for (I i = j.begin (); i < j.end (); i += 3) + baz (*i); +} + +void +f2 (J j) +{ + I i; +#pragma omp distribute parallel for default(none) + for (i = j.begin (); i < j.end (); ++i) + baz (*i); +} + +template +void +f3 (J j) +{ +#pragma omp distribute parallel for default(none) + for (I i = j.begin (); i < j.end (); i += 6) + baz (*i); +} + +template +void +f4 (J j) +{ + I i; +#pragma omp distribute parallel for default(none) + for (i = j.begin (); i < j.end (); i += 9) + baz (*i); +} + +template +void +f5 (J j) +{ +#pragma omp distribute parallel for default(none) + for (I i = j.begin (); i < j.end (); i += 4) + baz (*i); +} + +template +void +f6 (J j) +{ + I i; +#pragma omp distribute parallel for default(none) + for (i = j.begin (); i < j.end (); i += 7) + baz (*i); +} + +#pragma omp end declare target + +#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]; + for (int i = 0; i < 2000; i++) + a[i] = i; + #pragma omp target data map (to: a) + { + #pragma omp target teams map (tofrom: results) + { + J j (&a[75], &a[1945]); + f1 (j); + } + check (i >= 75 && i < 1945 && (i - 75) % 3 == 0); + #pragma omp target teams map (tofrom: results) + { + J j (&a[63], &a[1949]); + f2 (j); + } + check (i >= 63 && i < 1949); + #pragma omp target teams map (tofrom: results) + { + J j (&a[58], &a[1979]); + f3 <2> (j); + } + check (i >= 58 && i < 1979 && (i - 58) % 6 == 0); + #pragma omp target teams map (tofrom: results) + { + J j (&a[59], &a[1981]); + f4 <9> (j); + } + check (i >= 59 && i < 1981 && (i - 59) % 9 == 0); + #pragma omp target teams map (tofrom: results) + { + J j (&a[52], &a[1972]); + f5 (j); + } + check (i >= 52 && i < 1972 && (i - 52) % 4 == 0); + #pragma omp target teams map (tofrom: results) + { + J j (&a[31], &a[1827]); + f6 (j); + } + check (i >= 31 && i < 1827 && (i - 31) % 7 == 0); + } +}