This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[committed] Handle C++ random access iterators in loop construct, other C++ loop construct fixes


Hi!

The following patch fixes handling of C++ class random access iterators
and fixes also other issues found during that with OMP_LOOP C++
genericization and gimplification.

Bootstrapped/regtested on x86_64-linux and i686-linux, committed to trunk.

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.
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.

--- gcc/tree.h.jj	2019-08-05 09:58:05.060531603 +0200
+++ gcc/tree.h	2019-08-05 14:13:40.005834106 +0200
@@ -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.  */
--- gcc/gimplify.c.jj	2019-08-05 09:57:55.603676252 +0200
+++ gcc/gimplify.c	2019-08-05 14:15:52.821843830 +0200
@@ -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_s
 
   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_s
 	}
 
       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_s
 	  {
 	    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_s
 	  }
     }
 
-  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_s
 		   || !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 +11509,8 @@ gimplify_omp_for (tree *expr_p, gimple_s
 
   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 +11525,8 @@ gimplify_omp_for (tree *expr_p, gimple_s
   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 +11566,11 @@ gimplify_omp_for (tree *expr_p, gimple_s
     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 +11671,7 @@ gimplify_omp_for (tree *expr_p, gimple_s
 	     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 +11994,21 @@ gimplify_omp_loop (tree *expr_p, gimple_
 	  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 +12025,29 @@ gimplify_omp_loop (tree *expr_p, gimple_
 	    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:
--- gcc/omp-low.c.jj	2019-08-05 09:57:55.667675273 +0200
+++ gcc/omp-low.c	2019-08-05 14:13:40.006834091 +0200
@@ -5139,8 +5139,17 @@ lower_rec_input_clauses (tree clauses, g
 		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, g
 			}
 
 		      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,
 
 	  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))
--- gcc/cp/parser.c.jj	2019-08-05 09:57:55.223682065 +0200
+++ gcc/cp/parser.c	2019-08-05 14:13:40.000834181 +0200
@@ -37390,7 +37390,8 @@ cp_parser_omp_for_loop (cp_parser *parse
 	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 ; )
@@ -37450,12 +37451,12 @@ cp_parser_omp_for_loop (cp_parser *parse
 	    }
 	  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)
--- gcc/cp/semantics.c.jj	2019-08-05 09:57:55.294680979 +0200
+++ gcc/cp/semantics.c	2019-08-05 14:13:40.002834151 +0200
@@ -8420,24 +8420,25 @@ handle_omp_for_class_iterator (int i, lo
 
   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));
@@ -8457,7 +8458,7 @@ handle_omp_for_class_iterator (int i, lo
   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;
@@ -8473,6 +8474,28 @@ handle_omp_for_class_iterator (int i, lo
       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 ();
@@ -8823,9 +8846,7 @@ finish_omp_for (location_t locus, enum t
     omp_for = NULL_TREE;
 
   if (omp_for == NULL)
-    {
-      return NULL;
-    }
+    return NULL;
 
   add_stmt (omp_for);
 
@@ -8924,6 +8945,16 @@ finish_omp_for (location_t locus, enum t
 	      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;
 }
--- gcc/cp/cp-gimplify.c.jj	2019-08-05 09:57:55.065684482 +0200
+++ gcc/cp/cp-gimplify.c	2019-08-05 14:13:40.002834151 +0200
@@ -796,6 +796,7 @@ cp_gimplify_expr (tree *expr_p, gimple_s
     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_subtr
 
   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
     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_se
   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_se
   /* 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)
--- gcc/cp/pt.c.jj	2019-08-05 09:58:07.744490548 +0200
+++ gcc/cp/pt.c	2019-08-05 14:13:40.004834121 +0200
@@ -16404,6 +16404,7 @@ tsubst_omp_clauses (tree clauses, enum c
 	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 *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,
 	}
       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)
--- gcc/cp/constexpr.c.jj	2019-08-05 11:19:43.447805487 +0200
+++ gcc/cp/constexpr.c	2019-08-05 14:13:40.001834166 +0200
@@ -6437,6 +6437,7 @@ potential_constant_expression_1 (tree t,
     case OMP_SIMD:
     case OMP_DISTRIBUTE:
     case OMP_TASKLOOP:
+    case OMP_LOOP:
     case OMP_TEAMS:
     case OMP_TARGET_DATA:
     case OMP_TARGET:
--- libgomp/testsuite/libgomp.c++/loop-13.C.jj	2019-08-05 14:13:40.007834076 +0200
+++ libgomp/testsuite/libgomp.c++/loop-13.C	2019-08-05 14:13:40.007834076 +0200
@@ -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);
+}
--- libgomp/testsuite/libgomp.c++/loop-14.C.jj	2019-08-05 14:18:53.403137781 +0200
+++ libgomp/testsuite/libgomp.c++/loop-14.C	2019-08-05 14:27:30.761383733 +0200
@@ -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);
+}
--- libgomp/testsuite/libgomp.c++/loop-15.C.jj	2019-08-05 15:38:31.218435198 +0200
+++ libgomp/testsuite/libgomp.c++/loop-15.C	2019-08-05 16:01:15.093254279 +0200
@@ -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);
+}

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]