From patchwork Tue Jul 10 07:18:18 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 941839 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-481260-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="TVLk9m5B"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41Ptpj5HTgz9rxs for ; Tue, 10 Jul 2018 17:18:36 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:reply-to:mime-version:content-type; q=dns; s=default; b=WuZAtsFzszB/FxZgcy4BNsbrGpN8LKOQMphRwK4qUfR c3Jkc9ua6ZGU9bQGYXcVEjDT0WB0/e7qe6YWT+7uLLjRQ74BtGEkwo2exTs6MmrB O/gdzkJ3KWL59mxWVjwXnv3gGtuT2rMUOS3c/KLbdtorrmUWwuuyx5IQB5KWaGn0 = DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:reply-to:mime-version:content-type; s=default; bh=e3CChPcrC3s/+paKYf59tFsWQCo=; b=TVLk9m5Bb9Vd7tgem qNcjxTN8L6Ke0ofp1b/YTQE3dhq/aiWLub2dbcZJk36klrAAD5pl24x2QwA+lQ9F 00wt8gpvZodrSqPST/GGDL7cM5JKjMF0cVIIQjYEhUMgnIq1lDQVW7XbZ+tQ2FkY vJgzof1z+g4gFL+vKgIKD3uUGo= Received: (qmail 35399 invoked by alias); 10 Jul 2018 07:18:28 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 35382 invoked by uid 89); 10 Jul 2018 07:18:26 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-10.9 required=5.0 tests=BAYES_00, GIT_PATCH_2, GIT_PATCH_3, KAM_LAZY_DOMAIN_SECURITY, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=decl_uid X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 10 Jul 2018 07:18:23 +0000 Received: from smtp.corp.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.26]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id E2D1F3082A29 for ; Tue, 10 Jul 2018 07:18:21 +0000 (UTC) Received: from tucnak.zalov.cz (ovpn-117-71.ams2.redhat.com [10.36.117.71]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 63FBD30012C2 for ; Tue, 10 Jul 2018 07:18:21 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.15.2/8.15.2) with ESMTP id w6A7IJfk027397 for ; Tue, 10 Jul 2018 09:18:19 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.15.2/8.15.2/Submit) id w6A7IIr2027396 for gcc-patches@gcc.gnu.org; Tue, 10 Jul 2018 09:18:18 +0200 Date: Tue, 10 Jul 2018 09:18:18 +0200 From: Jakub Jelinek To: gcc-patches@gcc.gnu.org Subject: [committed] Fix OpenMP class iterators in distribute parallel for (PR c++/86443) Message-ID: <20180710071818.GB7166@tucnak> Reply-To: Jakub Jelinek MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.9.2 (2017-12-15) X-IsSubscribed: yes Hi! While working on OpenMP 5.0 range-for support, I've discovered that even for normal class iterators distribute parallel for gimplification ICEs in several ways (other composite loop constructs work only because class iterators are not allowed on them). The problem is that the FEs emit the code that needs to be done before computing number of the iterations around the innermost construct, which we then wrap into OMP_PARALLEL and OMP_DISTRIBUTE and then we want to compute number of iterations on the OMP_DISTRIBUTE. The following patch fixes it by detecting these cases and moving the outer composite constructs right around the innermost one. Bootstrapped/regtested on x86_64-linux and i686-linux, committed to trunk. 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. 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. Jakub --- gcc/gimplify.c.jj 2018-07-07 09:45:42.133890332 +0200 +++ gcc/gimplify.c 2018-07-09 15:47:14.587400243 +0200 @@ -9532,24 +9532,53 @@ gimplify_omp_task (tree *expr_p, gimple_ } /* 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_s 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_s } } - 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_s /* 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_s 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_s 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_s 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_s 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) --- gcc/c-family/c-omp.c.jj 2018-07-05 11:41:51.994718940 +0200 +++ gcc/c-family/c-omp.c 2018-07-09 13:29:59.032898924 +0200 @@ -827,7 +827,9 @@ c_omp_check_loop_iv_r (tree *tp, int *wa { 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 dec 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; --- gcc/cp/semantics.c.jj 2018-07-05 11:41:51.798718714 +0200 +++ gcc/cp/semantics.c 2018-07-09 13:29:59.030898921 +0200 @@ -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, lo 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 t { 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 t } 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; --- gcc/cp/pt.c.jj 2018-07-05 11:41:51.750718660 +0200 +++ gcc/cp/pt.c 2018-07-09 13:29:59.028898919 +0200 @@ -16267,7 +16267,12 @@ tsubst_omp_for_iterator (tree t, int i, 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); --- libgomp/testsuite/libgomp.c++/for-15.C.jj 2018-07-09 17:19:46.206382978 +0200 +++ libgomp/testsuite/libgomp.c++/for-15.C 2018-07-09 17:19:57.937398899 +0200 @@ -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); + } +}