aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2019-08-06 09:26:32 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2019-08-06 09:26:32 +0200
commitd81ab49d0586fca0f3ee2f49c4581dd02508fcca (patch)
treed3d4e04d7c7e987c478e88417ded02a08e3e8aad
parent7551a6e467c64b3155d5b8f005cd7ea7143b21f3 (diff)
downloadgcc-d81ab49d0586fca0f3ee2f49c4581dd02508fcca.zip
gcc-d81ab49d0586fca0f3ee2f49c4581dd02508fcca.tar.gz
gcc-d81ab49d0586fca0f3ee2f49c4581dd02508fcca.tar.bz2
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
-rw-r--r--gcc/ChangeLog26
-rw-r--r--gcc/cp/ChangeLog25
-rw-r--r--gcc/cp/constexpr.c1
-rw-r--r--gcc/cp/cp-gimplify.c12
-rw-r--r--gcc/cp/parser.c11
-rw-r--r--gcc/cp/pt.c9
-rw-r--r--gcc/cp/semantics.c53
-rw-r--r--gcc/gimplify.c80
-rw-r--r--gcc/omp-low.c29
-rw-r--r--gcc/tree.h9
-rw-r--r--libgomp/ChangeLog6
-rw-r--r--libgomp/testsuite/libgomp.c++/loop-13.C298
-rw-r--r--libgomp/testsuite/libgomp.c++/loop-14.C301
-rw-r--r--libgomp/testsuite/libgomp.c++/loop-15.C417
14 files changed, 1237 insertions, 40 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index f19091c..ccb7253 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,29 @@
+2019-08-06 Jakub Jelinek <jakub@redhat.com>
+
+ * 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 <kito.cheng@sifive.com>
* gcc/config/riscv/multilib-generator: (canonical_order): New.
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 049863e..98e3b3f 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,28 @@
+2019-08-06 Jakub Jelinek <jakub@redhat.com>
+
+ * 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 <polacek@redhat.com>
DR 2413 - typename in conversion-function-ids.
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 75df984..36a6633 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 b4863e2..065dcb7 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 83e6d24..79da7b5 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 e671fe1..903e589 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 d151d3d..fa69624 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 6a1a7f0..10b9b68 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 5d1b88c..4a6ea0a 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 d5fb3b2..ce75b0c 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 5adcd74..0331c51 100644
--- a/libgomp/ChangeLog
+++ b/libgomp/ChangeLog
@@ -1,3 +1,9 @@
+2019-08-06 Jakub Jelinek <jakub@redhat.com>
+
+ * 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 <jakub@redhat.com>
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 0000000..663212c
--- /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 <typename T>
+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 <typename S> friend bool operator == (I<S> &, I<S> &);
+ template <typename S> friend bool operator == (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator < (I<S> &, I<S> &);
+ template <typename S> friend bool operator < (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator <= (I<S> &, I<S> &);
+ template <typename S> friend bool operator <= (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator > (I<S> &, I<S> &);
+ template <typename S> friend bool operator > (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator >= (I<S> &, I<S> &);
+ template <typename S> friend bool operator >= (const I<S> &, const I<S> &);
+ template <typename S> friend typename I<S>::difference_type operator - (I<S> &, I<S> &);
+ template <typename S> friend typename I<S>::difference_type operator - (const I<S> &, const I<S> &);
+ template <typename S> friend I<S> operator + (typename I<S>::difference_type , const I<S> &);
+private:
+ T *p;
+};
+template <typename T> I<T>::I () : p (0) {}
+template <typename T> I<T>::~I () {}
+template <typename T> I<T>::I (T *x) : p (x) {}
+template <typename T> I<T>::I (const I &x) : p (x.p) {}
+template <typename T> T &I<T>::operator * () { return *p; }
+template <typename T> T *I<T>::operator -> () { return p; }
+template <typename T> T &I<T>::operator [] (const difference_type &x) const { return p[x]; }
+template <typename T> I<T> &I<T>::operator = (const I &x) { p = x.p; return *this; }
+template <typename T> I<T> &I<T>::operator ++ () { ++p; return *this; }
+template <typename T> I<T> I<T>::operator ++ (int) { return I (p++); }
+template <typename T> I<T> &I<T>::operator -- () { --p; return *this; }
+template <typename T> I<T> I<T>::operator -- (int) { return I (p--); }
+template <typename T> I<T> &I<T>::operator += (const difference_type &x) { p += x; return *this; }
+template <typename T> I<T> &I<T>::operator -= (const difference_type &x) { p -= x; return *this; }
+template <typename T> I<T> I<T>::operator + (const difference_type &x) const { return I (p + x); }
+template <typename T> I<T> I<T>::operator - (const difference_type &x) const { return I (p - x); }
+template <typename T> bool operator == (I<T> &x, I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator == (const I<T> &x, const I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator != (I<T> &x, I<T> &y) { return !(x == y); }
+template <typename T> bool operator != (const I<T> &x, const I<T> &y) { return !(x == y); }
+template <typename T> bool operator < (I<T> &x, I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator < (const I<T> &x, const I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator <= (I<T> &x, I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator <= (const I<T> &x, const I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator > (I<T> &x, I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator > (const I<T> &x, const I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator >= (I<T> &x, I<T> &y) { return x.p >= y.p; }
+template <typename T> bool operator >= (const I<T> &x, const I<T> &y) { return x.p >= y.p; }
+template <typename T> typename I<T>::difference_type operator - (I<T> &x, I<T> &y) { return x.p - y.p; }
+template <typename T> typename I<T>::difference_type operator - (const I<T> &x, const I<T> &y) { return x.p - y.p; }
+template <typename T> I<T> operator + (typename I<T>::difference_type x, const I<T> &y) { return I<T> (x + y.p); }
+
+template <typename T>
+class J
+{
+public:
+ J(const I<T> &x, const I<T> &y) : b (x), e (y) {}
+ const I<T> &begin ();
+ const I<T> &end ();
+private:
+ I<T> b, e;
+};
+
+template <typename T> const I<T> &J<T>::begin () { return b; }
+template <typename T> const I<T> &J<T>::end () { return e; }
+
+int results[2000];
+
+template <typename T>
+static inline void
+baz (I<T> &i)
+{
+ results[*i]++;
+}
+
+void
+f1 (const I<int> &x, const I<int> &y)
+{
+#pragma omp parallel loop order(concurrent)
+ for (I<int> i = x; i <= y; i += 6)
+ baz (i);
+}
+
+void
+f2 (const I<int> &x, const I<int> &y)
+{
+ I<int> i;
+#pragma omp loop private(i) bind(parallel)
+ for (i = x; i < y - 1; i = 1 - 6 + 7 + i)
+ baz (i);
+}
+
+template <typename T>
+void
+f3 (const I<int> &x, const I<int> &y)
+{
+#pragma omp loop bind(thread) order(concurrent)
+ for (I<int> i = x; i <= y; i = i + 9 - 8)
+ baz (i);
+}
+
+template <typename T>
+void
+f4 (const I<int> &x, const I<int> &y)
+{
+ I<int> i;
+#pragma omp parallel loop lastprivate(i)
+ for (i = x + 2000 - 64; i > y + 10; --i)
+ baz (i);
+}
+
+void
+f5 (const I<int> &x, const I<int> &y)
+{
+#pragma omp loop bind(teams)
+ for (I<int> i = x + 2000 - 64; i > y + 10; i -= 10)
+ baz (i);
+}
+
+template <int N>
+void
+f6 (const I<int> &x, const I<int> &y)
+{
+ I<int> i;
+#pragma omp teams loop order(concurrent)
+ for (i = x + 2000 - 64; i > y + 10; i = i - 12 + 2)
+ {
+ I<int> j = i + N;
+ baz (j);
+ }
+}
+
+template <int N>
+void
+f7 (I<int> i, const I<int> &x, const I<int> &y)
+{
+#pragma omp master
+#pragma omp loop
+ for (i = x - 10; i <= y + 10; i += N)
+ baz (i);
+}
+
+template <int N>
+void
+f8 (J<int> j)
+{
+ I<int> i;
+#pragma omp parallel loop
+ for (i = j.begin (); i <= j.end () + N; i += 2)
+ baz (i);
+}
+
+template <typename T, int N>
+void
+f9 (const I<T> &x, const I<T> &y)
+{
+ I<T> i;
+#pragma omp loop bind(teams) private(i)
+ for (i = x; i <= y; i = i + N)
+ baz (i);
+}
+
+template <typename T, int N>
+void
+f10 (const I<T> &x, const I<T> &y)
+{
+ I<T> i;
+#pragma omp loop bind(thread) private(i)
+ for (i = x; i > y; i = i + N)
+ baz (i);
+}
+
+template <typename T>
+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 <typename T>
+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 <int N>
+struct K
+{
+ template <typename T>
+ 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<char> (&a[20], &a[1837]);
+ check (i >= 20 && i <= 1837);
+ f4<int> (&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<int> (), &a[12], &a[1800]);
+ check (i >= 2 && i <= 1808 && (i - 2) % 6 == 0);
+ f8<121> (J<int> (&a[14], &a[1803]));
+ check (i >= 14 && i <= 1924 && (i & 1) == 0);
+ #pragma omp teams
+ f9<int, 7> (&a[33], &a[1967]);
+ check (i >= 33 && i <= 1967 && (i - 33) % 7 == 0);
+ f10<int, -7> (&a[1939], &a[17]);
+ check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0);
+ f11<I<int> > (&a[16], &a[1981]);
+ check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0);
+ f12<I<int> > (&a[1761], &a[37]);
+ check (i > 37 && i <= 1761);
+ K<5>::f13<I<int> > (&a[1], &a[1935]);
+ check (i >= 1 && i <= 1936 && (i - 1) % 5 == 0);
+ #pragma omp teams
+ f9<long, 7> (&b[33], &b[1967]);
+ check (i >= 33 && i <= 1967 && (i - 33) % 7 == 0);
+ f10<long, -7> (&b[1939], &b[17]);
+ check (i >= 21 && i <= 1939 && (i - 21) % 7 == 0);
+ f11<I<long> > (&b[16], &b[1981]);
+ check (i >= 16 && i <= 1984 && (i - 16) % 3 == 0);
+ f12<I<long> > (&b[1761], &b[37]);
+ check (i > 37 && i <= 1761);
+ K<5>::f13<I<long> > (&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 0000000..191ab68
--- /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 <typename T>
+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 <typename S> friend bool operator == (I<S> &, I<S> &);
+ template <typename S> friend bool operator == (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator < (I<S> &, I<S> &);
+ template <typename S> friend bool operator < (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator <= (I<S> &, I<S> &);
+ template <typename S> friend bool operator <= (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator > (I<S> &, I<S> &);
+ template <typename S> friend bool operator > (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator >= (I<S> &, I<S> &);
+ template <typename S> friend bool operator >= (const I<S> &, const I<S> &);
+ template <typename S> friend typename I<S>::difference_type operator - (I<S> &, I<S> &);
+ template <typename S> friend typename I<S>::difference_type operator - (const I<S> &, const I<S> &);
+ template <typename S> friend I<S> operator + (typename I<S>::difference_type , const I<S> &);
+private:
+ T *p;
+};
+template <typename T> I<T>::I () : p (0) {}
+template <typename T> I<T>::~I () { p = (T *) 0; }
+template <typename T> I<T>::I (T *x) : p (x) {}
+template <typename T> I<T>::I (const I &x) : p (x.p) {}
+template <typename T> T &I<T>::operator * () { return *p; }
+template <typename T> T *I<T>::operator -> () { return p; }
+template <typename T> T &I<T>::operator [] (const difference_type &x) const { return p[x]; }
+template <typename T> I<T> &I<T>::operator = (const I &x) { p = x.p; return *this; }
+template <typename T> I<T> &I<T>::operator ++ () { ++p; return *this; }
+template <typename T> I<T> I<T>::operator ++ (int) { return I (p++); }
+template <typename T> I<T> &I<T>::operator -- () { --p; return *this; }
+template <typename T> I<T> I<T>::operator -- (int) { return I (p--); }
+template <typename T> I<T> &I<T>::operator += (const difference_type &x) { p += x; return *this; }
+template <typename T> I<T> &I<T>::operator -= (const difference_type &x) { p -= x; return *this; }
+template <typename T> I<T> I<T>::operator + (const difference_type &x) const { return I (p + x); }
+template <typename T> I<T> I<T>::operator - (const difference_type &x) const { return I (p - x); }
+template <typename T> bool operator == (I<T> &x, I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator == (const I<T> &x, const I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator != (I<T> &x, I<T> &y) { return !(x == y); }
+template <typename T> bool operator != (const I<T> &x, const I<T> &y) { return !(x == y); }
+template <typename T> bool operator < (I<T> &x, I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator < (const I<T> &x, const I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator <= (I<T> &x, I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator <= (const I<T> &x, const I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator > (I<T> &x, I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator > (const I<T> &x, const I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator >= (I<T> &x, I<T> &y) { return x.p >= y.p; }
+template <typename T> bool operator >= (const I<T> &x, const I<T> &y) { return x.p >= y.p; }
+template <typename T> typename I<T>::difference_type operator - (I<T> &x, I<T> &y) { return x.p - y.p; }
+template <typename T> typename I<T>::difference_type operator - (const I<T> &x, const I<T> &y) { return x.p - y.p; }
+template <typename T> I<T> operator + (typename I<T>::difference_type x, const I<T> &y) { return I<T> (x + y.p); }
+
+template <typename T>
+class J
+{
+public:
+ J(const I<T> &x, const I<T> &y) : b (x), e (y) {}
+ const I<T> &begin ();
+ const I<T> &end ();
+private:
+ I<T> b, e;
+};
+
+template <typename T> const I<T> &J<T>::begin () { return b; }
+template <typename T> const I<T> &J<T>::end () { return e; }
+
+int results[2000];
+
+template <typename T>
+static inline void
+baz (I<T> &i)
+{
+ results[*i]++;
+}
+
+I<int>
+f1 (const I<int> &x, const I<int> &y)
+{
+ I<int> 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<int> (i);
+}
+
+I<int>
+f2 (const I<int> &x, const I<int> &y)
+{
+ I<int> i;
+#pragma omp parallel loop bind(parallel)
+ for (i = x; i < y - 1; i = 1 - 6 + 7 + i)
+ baz (i);
+ return I<int> (i);
+}
+
+template <typename T>
+I<int>
+f3 (const I<int> &x, const I<int> &y)
+{
+ I<int> i;
+#pragma omp teams
+ #pragma omp loop order(concurrent)
+ for (i = x + 1000 - 64; i <= y - 10; i++)
+ baz (i);
+ return i;
+}
+
+template <typename T>
+I<int>
+f4 (const I<int> &x, const I<int> &y)
+{
+ I<int> i;
+#pragma omp teams loop lastprivate (i)
+ for (i = x + 2000 - 64; i > y + 10; --i)
+ baz (i);
+ return I<int> (i);
+}
+
+template <typename T>
+I<int>
+f5 (const I<int> &x, const I<int> &y)
+{
+ I<int> i;
+#pragma omp loop lastprivate (i) bind(thread)
+ for (i = x; i > y + T (6); i--)
+ baz (i);
+ return i;
+}
+
+template <typename T>
+I<int>
+f6 (const I<int> &x, const I<int> &y)
+{
+ I<int> i;
+#pragma omp loop bind(thread)
+ for (i = x - T (7); i > y; i -= T (2))
+ baz (i);
+ return I<int> (i);
+}
+
+template <int N>
+I<int>
+f7 (I<int> i, const I<int> &x, const I<int> &y)
+{
+#pragma omp parallel for lastprivate (i)
+ for (i = x - 10; i <= y + 10; i += N)
+ baz (i);
+ return I<int> (i);
+}
+
+template <int N>
+I<int>
+f8 (J<int> j)
+{
+ I<int> 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<int> i9;
+
+template <long N>
+I<int> &
+f9 (J<int> j)
+{
+#pragma omp loop bind(parallel)
+ for (i9 = j.begin () + N; i9 <= j.end () - N; i9 = i9 - N)
+ baz (i9);
+ return i9;
+}
+
+template <typename T, int N>
+I<T>
+f10 (const I<T> &x, const I<T> &y)
+{
+ I<T> i;
+#pragma omp parallel loop lastprivate (i)
+ for (i = x; i > y; i = i + N)
+ baz (i);
+ return i;
+}
+
+template <typename T, typename U>
+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 <typename T>
+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<int> (&a[10], &a[1971]) != 1962)
+ abort ();
+ check (i >= 946 && i <= 1961);
+ if (*f4<int> (&a[0], &a[30]) != 40)
+ abort ();
+ check (i > 40 && i <= 2000 - 64);
+ if (*f5<short> (&a[1931], &a[17]) != 23)
+ abort ();
+ check (i > 23 && i <= 1931);
+ if (*f6<long> (&a[1931], &a[17]) != 16)
+ abort ();
+ check (i > 17 && i <= 1924 && (i & 1) == 0);
+ if (*f7<6> (I<int> (), &a[12], &a[1800]) != 1814)
+ abort ();
+ check (i >= 2 && i <= 1808 && (i - 2) % 6 == 0);
+ if (*f8<121> (J<int> (&a[14], &a[1803])) != 1926)
+ abort ();
+ check (i >= 14 && i <= 1924 && (i & 1) == 0);
+ #pragma omp parallel
+ if (*f9<-3L> (J<int> (&a[27], &a[1761])) != 1767)
+ abort ();
+ check (i >= 24 && i <= 1764 && (i % 3) == 0);
+ if (*f10<int, -7> (&a[1939], &a[17]) != 14)
+ abort ();
+ check (i >= 21 && i <= 1939 && i % 7 == 0);
+ if (*f11<I<int>, short> (I<int> (), &a[71], &a[1941]) != 1943)
+ abort ();
+ check (i >= 73 && i <= 1938 && (i - 73) % 5 == 0);
+ if (*f12<I<int> > (&a[1761], &a[37]) != 37)
+ abort ();
+ check (i > 37 && i <= 1761);
+ if (*f10<long, -7> (&b[1939], &b[17]) != 14)
+ abort ();
+ check (i >= 21 && i <= 1939 && i % 7 == 0);
+ if (*f11<I<long>, short> (I<long> (), &b[71], &b[1941]) != 1943)
+ abort ();
+ check (i >= 73 && i <= 1938 && (i - 73) % 5 == 0);
+ if (*f12<I<long> > (&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 0000000..b523b9b
--- /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<typename T> struct tuple_size;
+ template<int, typename> struct tuple_element;
+}
+
+template <typename T>
+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 <typename S> friend bool operator == (I<S> &, I<S> &);
+ template <typename S> friend bool operator == (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator < (I<S> &, I<S> &);
+ template <typename S> friend bool operator < (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator <= (I<S> &, I<S> &);
+ template <typename S> friend bool operator <= (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator > (I<S> &, I<S> &);
+ template <typename S> friend bool operator > (const I<S> &, const I<S> &);
+ template <typename S> friend bool operator >= (I<S> &, I<S> &);
+ template <typename S> friend bool operator >= (const I<S> &, const I<S> &);
+ template <typename S> friend typename I<S>::difference_type operator - (I<S> &, I<S> &);
+ template <typename S> friend typename I<S>::difference_type operator - (const I<S> &, const I<S> &);
+ template <typename S> friend I<S> operator + (typename I<S>::difference_type , const I<S> &);
+private:
+ T *p;
+};
+template <typename T> I<T>::I () : p (0) {}
+template <typename T> I<T>::~I () {}
+template <typename T> I<T>::I (T *x) : p (x) {}
+template <typename T> I<T>::I (const I &x) : p (x.p) {}
+template <typename T> T &I<T>::operator * () { return *p; }
+template <typename T> T *I<T>::operator -> () { return p; }
+template <typename T> T &I<T>::operator [] (const difference_type &x) const { return p[x]; }
+template <typename T> I<T> &I<T>::operator = (const I &x) { p = x.p; return *this; }
+template <typename T> I<T> &I<T>::operator ++ () { ++p; return *this; }
+template <typename T> I<T> I<T>::operator ++ (int) { return I (p++); }
+template <typename T> I<T> &I<T>::operator -- () { --p; return *this; }
+template <typename T> I<T> I<T>::operator -- (int) { return I (p--); }
+template <typename T> I<T> &I<T>::operator += (const difference_type &x) { p += x; return *this; }
+template <typename T> I<T> &I<T>::operator -= (const difference_type &x) { p -= x; return *this; }
+template <typename T> I<T> I<T>::operator + (const difference_type &x) const { return I (p + x); }
+template <typename T> I<T> I<T>::operator - (const difference_type &x) const { return I (p - x); }
+template <typename T> bool operator == (I<T> &x, I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator == (const I<T> &x, const I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator != (I<T> &x, I<T> &y) { return !(x == y); }
+template <typename T> bool operator != (const I<T> &x, const I<T> &y) { return !(x == y); }
+template <typename T> bool operator < (I<T> &x, I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator < (const I<T> &x, const I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator <= (I<T> &x, I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator <= (const I<T> &x, const I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator > (I<T> &x, I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator > (const I<T> &x, const I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator >= (I<T> &x, I<T> &y) { return x.p >= y.p; }
+template <typename T> bool operator >= (const I<T> &x, const I<T> &y) { return x.p >= y.p; }
+template <typename T> typename I<T>::difference_type operator - (I<T> &x, I<T> &y) { return x.p - y.p; }
+template <typename T> typename I<T>::difference_type operator - (const I<T> &x, const I<T> &y) { return x.p - y.p; }
+template <typename T> I<T> operator + (typename I<T>::difference_type x, const I<T> &y) { return I<T> (x + y.p); }
+
+template <typename T>
+class J
+{
+public:
+ J(const I<T> &x, const I<T> &y) : b (x), e (y) {}
+ const I<T> &begin ();
+ const I<T> &end ();
+private:
+ I<T> b, e;
+};
+
+template <typename T> const I<T> &J<T>::begin () { return b; }
+template <typename T> const I<T> &J<T>::end () { return e; }
+
+template <typename T>
+class K
+{
+public:
+ K ();
+ ~K ();
+ template <int N> T &get () { if (N == 0) return c; else if (N == 1) return b; return a; }
+ T a, b, c;
+};
+
+template <typename T> K<T>::K () : a {}, b {}, c {} {}
+template <typename T> K<T>::~K () {}
+template <typename T> struct std::tuple_size<K<T>> { static constexpr int value = 3; };
+template <typename T, int N> struct std::tuple_element<N, K<T>> { using type = T; };
+
+template <typename T>
+class L
+{
+public:
+ L ();
+ ~L ();
+ T a, b, c;
+};
+
+template <typename T> L<T>::L () : a {}, b {}, c {} {}
+template <typename T> L<T>::~L () {}
+
+int a[2000];
+long b[40];
+short c[50];
+int d[1024];
+K<int> e[1089];
+L<int> f[1093];
+int results[2000];
+
+template <typename T>
+static inline void
+baz (I<T> &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<int> 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<K<int>> 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<L<int>> 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<K<int>> 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<L<int>> 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 <int N>
+void
+f10 ()
+{
+#pragma omp loop bind(teams)
+ for (auto i : a)
+ baz (i);
+}
+
+template <int N>
+void
+f11 ()
+{
+#pragma omp loop bind(thread)
+ for (auto &i : a)
+ if (&i != &a[i])
+ abort ();
+ else
+ baz (i);
+}
+
+template <int N>
+void
+f12 ()
+{
+#pragma omp parallel loop collapse(3) default(none) shared(a, b, c) bind(parallel)
+ for (auto &i : b)
+ for (I<int> j = I<int> (&a[9]); j < I<int> (&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 <typename T>
+void
+f13 (J<T> j)
+{
+#pragma omp loop bind(thread)
+ for (auto &i : j)
+ if (&i != &a[i])
+ abort ();
+ else
+ baz (i);
+}
+
+template <int N>
+void
+f14 ()
+{
+#pragma omp parallel loop default(none) shared(d, results)
+ for (auto i : d)
+ results[i % N] += 2 * ((unsigned) i >> 10) + 1;
+}
+
+template <typename T>
+void
+f15 (J<K<T>> 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 <typename T>
+void
+f16 (J<L<T>> 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 <int N>
+void
+f17 (J<K<int>> 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 <int N>
+void
+f18 (J<L<int>> 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<int> (&a[14], &a[1803]));
+ check (i >= 14 && i < 1803);
+ f5 ();
+ check (i >= 0 && i < 1024);
+ #pragma omp parallel
+ f6 (J<K<int>> (&e[19], &e[1029]));
+ check (i >= 19 && i < 1029);
+ f7 (J<L<int>> (&f[15], &f[1091]));
+ check (i >= 15 && i < 1091);
+ f8 (J<K<int>> (&e[27], &e[1037]));
+ check (i >= 27 && i < 1037);
+ f9 (J<L<int>> (&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<int> (&a[24], &a[1703]));
+ check (i >= 24 && i < 1703);
+ f14 <1024> ();
+ check (i >= 0 && i < 1024);
+ f15 (J<K<int>> (&e[39], &e[929]));
+ check (i >= 39 && i < 929);
+ #pragma omp parallel
+ f16 (J<L<int>> (&f[17], &f[1071]));
+ check (i >= 17 && i < 1071);
+ f17 <3> (J<K<int>> (&e[7], &e[1017]));
+ check (i >= 7 && i < 1017);
+ f18 <5> (J<L<int>> (&f[121], &f[1010]));
+ check (i >= 121 && i < 1010);
+}