tree.h (OMP_CLAUSE_LASTPRIVATE_TASKLOOP_IV): Rename to ...
authorJakub Jelinek <jakub@redhat.com>
Tue, 6 Aug 2019 07:26:32 +0000 (09:26 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Tue, 6 Aug 2019 07:26:32 +0000 (09:26 +0200)
* 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

14 files changed:
gcc/ChangeLog
gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/cp/cp-gimplify.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/gimplify.c
gcc/omp-low.c
gcc/tree.h
libgomp/ChangeLog
libgomp/testsuite/libgomp.c++/loop-13.C [new file with mode: 0644]
libgomp/testsuite/libgomp.c++/loop-14.C [new file with mode: 0644]
libgomp/testsuite/libgomp.c++/loop-15.C [new file with mode: 0644]

index f19091c..ccb7253 100644 (file)
@@ -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.
index 049863e..98e3b3f 100644 (file)
@@ -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.
index 75df984..36a6633 100644 (file)
@@ -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:
index b4863e2..065dcb7 100644 (file)
@@ -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)
index 83e6d24..79da7b5 100644 (file)
@@ -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)
index e671fe1..903e589 100644 (file)
@@ -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)
index d151d3d..fa69624 100644 (file)
@@ -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;
 }
index 6a1a7f0..10b9b68 100644 (file)
@@ -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:
index 5d1b88c..4a6ea0a 100644 (file)
@@ -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))
index d5fb3b2..ce75b0c 100644 (file)
@@ -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.  */
index 5adcd74..0331c51 100644 (file)
@@ -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 (file)
index 0000000..663212c
--- /dev/null
@@ -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 (file)
index 0000000..191ab68
--- /dev/null
@@ -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 (file)
index 0000000..b523b9b
--- /dev/null
@@ -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);
+}