public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [committed] Implement OpenMP 5.0 lastprivate(conditional:) for #pragma omp for
@ 2019-05-24 21:34 Jakub Jelinek
  0 siblings, 0 replies; only message in thread
From: Jakub Jelinek @ 2019-05-24 21:34 UTC (permalink / raw)
  To: gcc-patches

Hi!

The following patch implements lastprivate clause with conditional modifier
for #pragma omp for (when not combined with parallel).
Next week I'll try to address combined parallel for, sections, simd and for
simd.

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

2019-05-24  Jakub Jelinek  <jakub@redhat.com>

	* tree-core.h (enum omp_clause_code): Add OMP_CLAUSE__CONDTEMP_.
	* tree.h (OMP_CLAUSE_DECL): Use OMP_CLAUSE__CONDTEMP_ instead of
	OMP_CLAUSE__REDUCTEMP_.
	* tree.c (omp_clause_num_ops, omp_clause_code_name): Add
	OMP_CLAUSE__CONDTEMP_.
	(walk_tree_1): Handle OMP_CLAUSE__CONDTEMP_.
	* tree-pretty-print.c (dump_omp_clause): Likewise.
	* tree-nested.c (convert_nonlocal_omp_clauses,
	convert_local_omp_clauses): Likewise.
	* gimplify.c (enum gimplify_omp_var_data): Use hexadecimal constants
	instead of decimal.  Add GOVD_LASTPRIVATE_CONDITIONAL.
	(gimplify_scan_omp_clauses): Don't reject lastprivate conditional
	on OMP_FOR.
	(gimplify_omp_for): Warn and disable conditional modifier from
	lastprivate on loop iterators.
	* omp-general.h (struct omp_for_data): Add lastprivate_conditional
	member.
	* omp-general.c (omp_extract_for_data): Initialize it.
	* omp-low.c (struct omp_context): Add lastprivate_conditional_map
	member.
	(delete_omp_context): Delete it.
	(lower_lastprivate_conditional_clauses): New function.
	(lower_lastprivate_clauses): Add BODY_P and CSTMT_LIST arguments,
	handle lastprivate conditional clauses.
	(lower_reduction_clauses): Add CLIST argument, emit it into
	the critical section if any.
	(lower_omp_sections): Adjust lower_lastprivate_clauses and
	lower_reduction_clauses callers.
	(lower_omp_for_lastprivate): Add CLIST argument, pass it through
	to lower_lastprivate_clauses.
	(lower_omp_for): Call lower_lastprivate_conditional_clauses, adjust
	lower_omp_for_lastprivate and lower_reduction_clauses callers, emit
	clist into a critical section if not emitted there already by
	lower_reduction_clauses.
	(lower_omp_taskreg, lower_omp_teams): Adjust lower_reduction_clauses
	callers.
	(lower_omp_1): Handle GIMPLE_ASSIGNs storing into lastprivate
	conditional variables.
	* omp-expand.c (determine_parallel_type): Punt if OMP_CLAUSE__CONDTEMP_
	clause is present.
	(expand_omp_for_generic, expand_omp_for_static_nochunk,
	expand_omp_for_static_chunk): Handle lastprivate conditional.
	(expand_omp_for): Handle fd.lastprivate_conditional like
	fd.have_reductemp.
gcc/testsuite/
	* c-c++-common/gomp/lastprivate-conditional-2.c (foo): Don't expect
	sorry for omp for.
	* c-c++-common/gomp/lastprivate-conditional-3.c: New test.
libgomp/
	* testsuite/libgomp.c-c++-common/lastprivate-conditional-1.c: New test.
	* testsuite/libgomp.c-c++-common/lastprivate-conditional-2.c: New test.

--- gcc/tree-core.h.jj	2019-05-24 10:54:49.447682115 +0200
+++ gcc/tree-core.h	2019-05-24 12:23:22.535364602 +0200
@@ -343,6 +343,9 @@ enum omp_clause_code {
   /* Internal clause: temporary for task reductions.  */
   OMP_CLAUSE__REDUCTEMP_,
 
+  /* Internal clause: temporary for lastprivate(conditional:).  */
+  OMP_CLAUSE__CONDTEMP_,
+
   /* OpenACC/OpenMP clause: if (scalar-expression).  */
   OMP_CLAUSE_IF,
 
--- gcc/tree.h.jj	2019-05-24 10:54:49.781676629 +0200
+++ gcc/tree.h	2019-05-24 12:23:22.528364717 +0200
@@ -1439,7 +1439,7 @@ class auto_suppress_location_wrappers
 #define OMP_CLAUSE_DECL(NODE)      					\
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE),	\
 					      OMP_CLAUSE_PRIVATE,	\
-					      OMP_CLAUSE__REDUCTEMP_), 0)
+					      OMP_CLAUSE__CONDTEMP_), 0)
 #define OMP_CLAUSE_HAS_LOCATION(NODE) \
   (LOCATION_LOCUS ((OMP_CLAUSE_CHECK (NODE))->omp_clause.locus)		\
   != UNKNOWN_LOCATION)
--- gcc/tree.c.jj	2019-05-24 10:54:49.734677400 +0200
+++ gcc/tree.c	2019-05-24 12:23:22.532364651 +0200
@@ -308,6 +308,7 @@ unsigned const char omp_clause_num_ops[]
   0, /* OMP_CLAUSE_SEQ  */
   1, /* OMP_CLAUSE__LOOPTEMP_  */
   1, /* OMP_CLAUSE__REDUCTEMP_  */
+  1, /* OMP_CLAUSE__CONDTEMP_  */
   1, /* OMP_CLAUSE_IF  */
   1, /* OMP_CLAUSE_NUM_THREADS  */
   1, /* OMP_CLAUSE_SCHEDULE  */
@@ -385,6 +386,7 @@ const char * const omp_clause_code_name[
   "seq",
   "_looptemp_",
   "_reductemp_",
+  "_condtemp_",
   "if",
   "num_threads",
   "schedule",
@@ -12304,6 +12306,7 @@ walk_tree_1 (tree *tp, walk_tree_fn func
 	case OMP_CLAUSE_IS_DEVICE_PTR:
 	case OMP_CLAUSE__LOOPTEMP_:
 	case OMP_CLAUSE__REDUCTEMP_:
+	case OMP_CLAUSE__CONDTEMP_:
 	case OMP_CLAUSE__SIMDUID_:
 	  WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, 0));
 	  /* FALLTHRU */
--- gcc/tree-pretty-print.c.jj	2019-05-24 10:54:49.507681129 +0200
+++ gcc/tree-pretty-print.c	2019-05-24 12:23:22.529364700 +0200
@@ -466,6 +466,9 @@ dump_omp_clause (pretty_printer *pp, tre
     case OMP_CLAUSE__REDUCTEMP_:
       name = "_reductemp_";
       goto print_remap;
+    case OMP_CLAUSE__CONDTEMP_:
+      name = "_condtemp_";
+      goto print_remap;
     case OMP_CLAUSE_TO_DECLARE:
       name = "to";
       goto print_remap;
--- gcc/tree-nested.c.jj	2019-05-24 10:54:49.674678385 +0200
+++ gcc/tree-nested.c	2019-05-24 12:23:22.526364750 +0200
@@ -1369,6 +1369,7 @@ convert_nonlocal_omp_clauses (tree *pcla
 	     function decomposition happens before that.  */
 	case OMP_CLAUSE__LOOPTEMP_:
 	case OMP_CLAUSE__REDUCTEMP_:
+	case OMP_CLAUSE__CONDTEMP_:
 	case OMP_CLAUSE__SIMDUID_:
 	case OMP_CLAUSE__GRIDDIM_:
 	case OMP_CLAUSE__SIMT_:
@@ -2096,6 +2097,7 @@ convert_local_omp_clauses (tree *pclause
 	     function decomposition happens before that.  */
 	case OMP_CLAUSE__LOOPTEMP_:
 	case OMP_CLAUSE__REDUCTEMP_:
+	case OMP_CLAUSE__CONDTEMP_:
 	case OMP_CLAUSE__SIMDUID_:
 	case OMP_CLAUSE__GRIDDIM_:
 	case OMP_CLAUSE__SIMT_:
--- gcc/gimplify.c.jj	2019-05-24 10:54:49.396682952 +0200
+++ gcc/gimplify.c	2019-05-24 12:23:22.536364585 +0200
@@ -71,47 +71,50 @@ static hash_set<tree> *asan_poisoned_var
 
 enum gimplify_omp_var_data
 {
-  GOVD_SEEN = 1,
-  GOVD_EXPLICIT = 2,
-  GOVD_SHARED = 4,
-  GOVD_PRIVATE = 8,
-  GOVD_FIRSTPRIVATE = 16,
-  GOVD_LASTPRIVATE = 32,
-  GOVD_REDUCTION = 64,
-  GOVD_LOCAL = 128,
-  GOVD_MAP = 256,
-  GOVD_DEBUG_PRIVATE = 512,
-  GOVD_PRIVATE_OUTER_REF = 1024,
-  GOVD_LINEAR = 2048,
-  GOVD_ALIGNED = 4096,
+  GOVD_SEEN = 0x000001,
+  GOVD_EXPLICIT = 0x000002,
+  GOVD_SHARED = 0x000004,
+  GOVD_PRIVATE = 0x000008,
+  GOVD_FIRSTPRIVATE = 0x000010,
+  GOVD_LASTPRIVATE = 0x000020,
+  GOVD_REDUCTION = 0x000040,
+  GOVD_LOCAL = 0x00080,
+  GOVD_MAP = 0x000100,
+  GOVD_DEBUG_PRIVATE = 0x000200,
+  GOVD_PRIVATE_OUTER_REF = 0x000400,
+  GOVD_LINEAR = 0x000800,
+  GOVD_ALIGNED = 0x001000,
 
   /* Flag for GOVD_MAP: don't copy back.  */
-  GOVD_MAP_TO_ONLY = 8192,
+  GOVD_MAP_TO_ONLY = 0x002000,
 
   /* Flag for GOVD_LINEAR or GOVD_LASTPRIVATE: no outer reference.  */
-  GOVD_LINEAR_LASTPRIVATE_NO_OUTER = 16384,
+  GOVD_LINEAR_LASTPRIVATE_NO_OUTER = 0x004000,
 
-  GOVD_MAP_0LEN_ARRAY = 32768,
+  GOVD_MAP_0LEN_ARRAY = 0x008000,
 
   /* Flag for GOVD_MAP, if it is always, to or always, tofrom mapping.  */
-  GOVD_MAP_ALWAYS_TO = 65536,
+  GOVD_MAP_ALWAYS_TO = 0x010000,
 
   /* Flag for shared vars that are or might be stored to in the region.  */
-  GOVD_WRITTEN = 131072,
+  GOVD_WRITTEN = 0x020000,
 
   /* Flag for GOVD_MAP, if it is a forced mapping.  */
-  GOVD_MAP_FORCE = 262144,
+  GOVD_MAP_FORCE = 0x040000,
 
   /* Flag for GOVD_MAP: must be present already.  */
-  GOVD_MAP_FORCE_PRESENT = 524288,
+  GOVD_MAP_FORCE_PRESENT = 0x080000,
 
   /* Flag for GOVD_MAP: only allocate.  */
-  GOVD_MAP_ALLOC_ONLY = 1048576,
+  GOVD_MAP_ALLOC_ONLY = 0x100000,
 
   /* Flag for GOVD_MAP: only copy back.  */
-  GOVD_MAP_FROM_ONLY = 2097152,
+  GOVD_MAP_FROM_ONLY = 0x200000,
 
-  GOVD_NONTEMPORAL = 4194304,
+  GOVD_NONTEMPORAL = 0x400000,
+
+  /* Flag for GOVD_LASTPRIVATE: conditional modifier.  */
+  GOVD_LASTPRIVATE_CONDITIONAL = 0x800000,
 
   GOVD_DATA_SHARE_CLASS = (GOVD_SHARED | GOVD_PRIVATE | GOVD_FIRSTPRIVATE
 			   | GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LINEAR
@@ -8141,9 +8144,17 @@ gimplify_scan_omp_clauses (tree *list_p,
 	      OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c) = 0;
 	    }
 	  if (OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c))
-	    sorry_at (OMP_CLAUSE_LOCATION (c),
-		      "%<conditional%> modifier on %<lastprivate%> clause "
-		      "not supported yet");
+	    {
+	      if (code == OMP_FOR)
+		flags |= GOVD_LASTPRIVATE_CONDITIONAL;
+	      else
+		{
+		  sorry_at (OMP_CLAUSE_LOCATION (c),
+			    "%<conditional%> modifier on %<lastprivate%> "
+			    "clause not supported yet");
+		  OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c) = 0;
+		}
+	    }
 	  if (outer_ctx
 	      && (outer_ctx->region_type == ORT_COMBINED_PARALLEL
 		  || ((outer_ctx->region_type & ORT_COMBINED_TEAMS)
@@ -10772,7 +10783,22 @@ gimplify_omp_for (tree *expr_p, gimple_s
 			  1 + (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt))
 			       != 1));
 	  if (n != NULL && (n->value & GOVD_DATA_SHARE_CLASS) != 0)
-	    omp_notice_variable (gimplify_omp_ctxp, decl, true);
+	    {
+	      omp_notice_variable (gimplify_omp_ctxp, decl, true);
+	      if (n->value & GOVD_LASTPRIVATE_CONDITIONAL)
+		for (tree c3 = omp_find_clause (OMP_FOR_CLAUSES (for_stmt),
+						OMP_CLAUSE_LASTPRIVATE);
+		     c3; c3 = omp_find_clause (OMP_CLAUSE_CHAIN (c3),
+					       OMP_CLAUSE_LASTPRIVATE))
+		  if (OMP_CLAUSE_DECL (c3) == decl)
+		    {
+		      warning_at (OMP_CLAUSE_LOCATION (c3), 0,
+				  "conditional %<lastprivate%> on loop "
+				  "iterator %qD ignored", decl);
+		      OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c3) = 0;
+		      n->value &= ~GOVD_LASTPRIVATE_CONDITIONAL;
+		    }
+	    }
 	  else if (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) == 1)
 	    {
 	      c = build_omp_clause (input_location, OMP_CLAUSE_LINEAR);
@@ -11007,7 +11033,24 @@ gimplify_omp_for (tree *expr_p, gimple_s
 	    }
 	}
       else if (omp_is_private (gimplify_omp_ctxp, decl, 0))
-	omp_notice_variable (gimplify_omp_ctxp, decl, true);
+	{
+	  omp_notice_variable (gimplify_omp_ctxp, decl, true);
+	  splay_tree_node n = splay_tree_lookup (gimplify_omp_ctxp->variables,
+						 (splay_tree_key) decl);
+	  if (n && (n->value & GOVD_LASTPRIVATE_CONDITIONAL))
+	    for (tree c3 = omp_find_clause (OMP_FOR_CLAUSES (for_stmt),
+					    OMP_CLAUSE_LASTPRIVATE);
+		 c3; c3 = omp_find_clause (OMP_CLAUSE_CHAIN (c3),
+					   OMP_CLAUSE_LASTPRIVATE))
+	      if (OMP_CLAUSE_DECL (c3) == decl)
+		{
+		  warning_at (OMP_CLAUSE_LOCATION (c3), 0,
+			      "conditional %<lastprivate%> on loop "
+			      "iterator %qD ignored", decl);
+		  OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c3) = 0;
+		  n->value &= ~GOVD_LASTPRIVATE_CONDITIONAL;
+		}
+	}
       else
 	omp_add_variable (gimplify_omp_ctxp, decl, GOVD_PRIVATE | GOVD_SEEN);
 
--- gcc/omp-general.h.jj	2019-05-24 10:54:49.613679387 +0200
+++ gcc/omp-general.h	2019-05-24 12:23:22.529364700 +0200
@@ -63,6 +63,7 @@ struct omp_for_data
   int collapse;  /* Collapsed loops, 1 for a non-collapsed loop.  */
   int ordered;
   bool have_nowait, have_ordered, simd_schedule, have_reductemp;
+  int lastprivate_conditional;
   unsigned char sched_modifiers;
   enum omp_clause_schedule_kind sched_kind;
   struct omp_for_data_loop *loops;
--- gcc/omp-general.c.jj	2019-05-24 10:54:49.562680225 +0200
+++ gcc/omp-general.c	2019-05-24 12:23:22.537364569 +0200
@@ -168,6 +168,7 @@ omp_extract_for_data (gomp_for *for_stmt
   fd->have_nowait = distribute || simd;
   fd->have_ordered = false;
   fd->have_reductemp = false;
+  fd->lastprivate_conditional = 0;
   fd->tiling = NULL_TREE;
   fd->collapse = 1;
   fd->ordered = 0;
@@ -220,6 +221,11 @@ omp_extract_for_data (gomp_for *for_stmt
 	break;
       case OMP_CLAUSE__REDUCTEMP_:
 	fd->have_reductemp = true;
+	break;
+      case OMP_CLAUSE_LASTPRIVATE:
+	if (OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (t))
+	  fd->lastprivate_conditional++;
+	break;
       default:
 	break;
       }
--- gcc/omp-low.c.jj	2019-05-24 10:54:49.962673655 +0200
+++ gcc/omp-low.c	2019-05-24 14:38:23.909551251 +0200
@@ -119,10 +119,14 @@ struct omp_context
      and then offsets (if constant, otherwise NULL) for each entry.  */
   vec<tree> task_reductions;
 
-  /* And a hash map from the reduction clauses to the registered array
+  /* A hash map from the reduction clauses to the registered array
      elts.  */
   hash_map<tree, unsigned> *task_reduction_map;
 
+  /* And a hash map from the lastprivate(conditional:) variables to their
+     corresponding tracking loop iteration variables.  */
+  hash_map<tree, tree> *lastprivate_conditional_map;
+
   /* Nesting depth of this context.  Used to beautify error messages re
      invalid gotos.  The outermost ctx is depth 1, with depth 0 being
      reserved for the main body of the function.  */
@@ -955,6 +959,8 @@ delete_omp_context (splay_tree_value val
       delete ctx->task_reduction_map;
     }
 
+  delete ctx->lastprivate_conditional_map;
+
   XDELETE (ctx);
 }
 
@@ -5358,18 +5364,72 @@ lower_rec_input_clauses (tree clauses, g
     }
 }
 
+/* Create temporary variables for lastprivate(conditional:) implementation
+   in context CTX with CLAUSES.  */
+
+static void
+lower_lastprivate_conditional_clauses (tree *clauses, omp_context *ctx)
+{
+  struct omp_for_data fd;
+  tree iter_type = NULL_TREE;
+  tree cond_ptr = NULL_TREE;
+  tree iter_var = NULL_TREE;
+  for (tree c = *clauses; c; c = OMP_CLAUSE_CHAIN (c))
+    if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
+	&& OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c))
+      {
+	if (iter_type == NULL)
+	  {
+	    omp_extract_for_data (as_a <gomp_for *> (ctx->stmt), &fd, NULL);
+	    iter_type = unsigned_type_for (fd.iter_type);
+	    cond_ptr = create_tmp_var_raw (build_pointer_type (iter_type));
+	    DECL_CONTEXT (cond_ptr) = current_function_decl;
+	    DECL_SEEN_IN_BIND_EXPR_P (cond_ptr) = 1;
+	    DECL_CHAIN (cond_ptr) = ctx->block_vars;
+	    ctx->block_vars = cond_ptr;
+	    iter_var = create_tmp_var_raw (iter_type);
+	    DECL_CONTEXT (iter_var) = current_function_decl;
+	    DECL_SEEN_IN_BIND_EXPR_P (iter_var) = 1;
+	    DECL_CHAIN (iter_var) = ctx->block_vars;
+	    ctx->block_vars = iter_var;
+	    tree c2
+	      = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE__CONDTEMP_);
+	    tree c3
+	      = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE__CONDTEMP_);
+	    OMP_CLAUSE_DECL (c2) = cond_ptr;
+	    OMP_CLAUSE_DECL (c3) = iter_var;
+	    OMP_CLAUSE_CHAIN (c2) = c3;
+	    OMP_CLAUSE_CHAIN (c3) = *clauses;
+	    *clauses = c2;
+	    ctx->lastprivate_conditional_map = new hash_map<tree, tree>;
+	  }
+	tree v = create_tmp_var_raw (iter_type);
+	DECL_CONTEXT (v) = current_function_decl;
+	DECL_SEEN_IN_BIND_EXPR_P (v) = 1;
+	DECL_CHAIN (v) = ctx->block_vars;
+	ctx->block_vars = v;
+	tree o = lookup_decl (OMP_CLAUSE_DECL (c), ctx);
+	ctx->lastprivate_conditional_map->put (o, v);
+      }
+}
+
 
 /* Generate code to implement the LASTPRIVATE clauses.  This is used for
    both parallel and workshare constructs.  PREDICATE may be NULL if it's
-   always true.   */
+   always true.  BODY_P is the sequence to insert early initialization
+   if needed, STMT_LIST is where the non-conditional lastprivate handling
+   goes into and CSTMT_LIST is a sequence that needs to be run in a critical
+   section.  */
 
 static void
-lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list,
+lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *body_p,
+			   gimple_seq *stmt_list, gimple_seq *cstmt_list,
 			   omp_context *ctx)
 {
   tree x, c, label = NULL, orig_clauses = clauses;
   bool par_clauses = false;
   tree simduid = NULL, lastlane = NULL, simtcond = NULL, simtlast = NULL;
+  unsigned HOST_WIDE_INT conditional_off = 0;
 
   /* Early exit if there are no lastprivate or linear clauses.  */
   for (; clauses ; clauses = OMP_CLAUSE_CHAIN (clauses))
@@ -5448,10 +5508,43 @@ lower_lastprivate_clauses (tree clauses,
       gimple_seq_add_stmt (stmt_list, gimple_build_label (label_true));
     }
 
+  tree cond_ptr = NULL_TREE;
   for (c = clauses; c ;)
     {
       tree var, new_var;
       location_t clause_loc = OMP_CLAUSE_LOCATION (c);
+      gimple_seq *this_stmt_list = stmt_list;
+      tree lab2 = NULL_TREE;
+
+      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
+	  && OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c))
+	{
+	  gcc_assert (body_p && ctx->lastprivate_conditional_map);
+	  if (cond_ptr == NULL_TREE)
+	    {
+	      cond_ptr = omp_find_clause (orig_clauses, OMP_CLAUSE__CONDTEMP_);
+	      cond_ptr = OMP_CLAUSE_DECL (cond_ptr);
+	    }
+	  tree type = TREE_TYPE (TREE_TYPE (cond_ptr));
+	  tree o = lookup_decl (OMP_CLAUSE_DECL (c), ctx);
+	  tree v = *ctx->lastprivate_conditional_map->get (o);
+	  gimplify_assign (v, build_zero_cst (type), body_p);
+	  this_stmt_list = cstmt_list;
+	  tree mem = build2 (MEM_REF, type, cond_ptr,
+			     build_int_cst (TREE_TYPE (cond_ptr),
+					    conditional_off));
+	  tree mem2 = copy_node (mem);
+	  conditional_off += tree_to_uhwi (TYPE_SIZE_UNIT (type));
+	  gimple_seq seq = NULL;
+	  mem = force_gimple_operand (mem, &seq, true, NULL_TREE);
+	  gimple_seq_add_seq (this_stmt_list, seq);
+	  tree lab1 = create_artificial_label (UNKNOWN_LOCATION);
+	  lab2 = create_artificial_label (UNKNOWN_LOCATION);
+	  gimple *g = gimple_build_cond (GT_EXPR, v, mem, lab1, lab2);
+	  gimple_seq_add_stmt (this_stmt_list, g);
+	  gimple_seq_add_stmt (this_stmt_list, gimple_build_label (lab1));
+	  gimplify_assign (mem2, v, this_stmt_list);
+	}
 
       if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
 	  || (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR
@@ -5493,7 +5586,7 @@ lower_lastprivate_clauses (tree clauses,
 						      2, simduid,
 						      TREE_OPERAND (val, 1));
 		      gimple_call_set_lhs (g, lastlane);
-		      gimple_seq_add_stmt (stmt_list, g);
+		      gimple_seq_add_stmt (this_stmt_list, g);
 		    }
 		  new_var = build4 (ARRAY_REF, TREE_TYPE (val),
 				    TREE_OPERAND (val, 0), lastlane,
@@ -5511,13 +5604,13 @@ lower_lastprivate_clauses (tree clauses,
 		  gcall *g = gimple_build_call_internal
 		    (IFN_GOMP_SIMT_LAST_LANE, 1, simtcond);
 		  gimple_call_set_lhs (g, simtlast);
-		  gimple_seq_add_stmt (stmt_list, g);
+		  gimple_seq_add_stmt (this_stmt_list, g);
 		}
 	      x = build_call_expr_internal_loc
 		(UNKNOWN_LOCATION, IFN_GOMP_SIMT_XCHG_IDX,
 		 TREE_TYPE (val), 2, val, simtlast);
 	      new_var = unshare_expr (new_var);
-	      gimplify_assign (new_var, x, stmt_list);
+	      gimplify_assign (new_var, x, this_stmt_list);
 	      new_var = unshare_expr (new_var);
 	    }
 
@@ -5525,7 +5618,7 @@ lower_lastprivate_clauses (tree clauses,
 	      && OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c))
 	    {
 	      lower_omp (&OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c), ctx);
-	      gimple_seq_add_seq (stmt_list,
+	      gimple_seq_add_seq (this_stmt_list,
 				  OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c));
 	      OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c) = NULL;
 	    }
@@ -5533,7 +5626,7 @@ lower_lastprivate_clauses (tree clauses,
 		   && OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c))
 	    {
 	      lower_omp (&OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c), ctx);
-	      gimple_seq_add_seq (stmt_list,
+	      gimple_seq_add_seq (this_stmt_list,
 				  OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c));
 	      OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c) = NULL;
 	    }
@@ -5553,8 +5646,12 @@ lower_lastprivate_clauses (tree clauses,
 	  if (omp_is_reference (var))
 	    new_var = build_simple_mem_ref_loc (clause_loc, new_var);
 	  x = lang_hooks.decls.omp_clause_assign_op (c, x, new_var);
-	  gimplify_and_add (x, stmt_list);
+	  gimplify_and_add (x, this_stmt_list);
+
+	  if (lab2)
+	    gimple_seq_add_stmt (this_stmt_list, gimple_build_label (lab2));
 	}
+
       c = OMP_CLAUSE_CHAIN (c);
       if (c == NULL && !par_clauses)
 	{
@@ -5802,10 +5899,15 @@ lower_oacc_reductions (location_t loc, t
   gimple_seq_add_seq (join_seq, after_join);
 }
 
-/* Generate code to implement the REDUCTION clauses.  */
+/* Generate code to implement the REDUCTION clauses, append it
+   to STMT_SEQP.  CLIST if non-NULL is a pointer to a sequence
+   that should be emitted also inside of the critical section,
+   in that case clear *CLIST afterwards, otherwise leave it as is
+   and let the caller emit it itself.  */
 
 static void
-lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp, omp_context *ctx)
+lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp,
+			 gimple_seq *clist, omp_context *ctx)
 {
   gimple_seq sub_seq = NULL;
   gimple *stmt;
@@ -6047,6 +6149,12 @@ lower_reduction_clauses (tree clauses, g
 
   gimple_seq_add_seq (stmt_seqp, sub_seq);
 
+  if (clist)
+    {
+      gimple_seq_add_seq (stmt_seqp, *clist);
+      *clist = NULL;
+    }
+
   stmt = gimple_build_call (builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_END),
 			    0);
   gimple_seq_add_stmt (stmt_seqp, stmt);
@@ -6684,7 +6792,7 @@ lower_omp_sections (gimple_stmt_iterator
 	{
 	  gimple_seq l = NULL;
 	  lower_lastprivate_clauses (gimple_omp_sections_clauses (stmt), NULL,
-				     &l, ctx);
+				     NULL, &l, NULL, ctx);
 	  gsi_insert_seq_after (&tgsi, l, GSI_CONTINUE_LINKING);
 	  gimple_omp_section_set_last (sec_start);
 	}
@@ -6697,7 +6805,8 @@ lower_omp_sections (gimple_stmt_iterator
   bind = gimple_build_bind (NULL, new_body, block);
 
   olist = NULL;
-  lower_reduction_clauses (gimple_omp_sections_clauses (stmt), &olist, ctx);
+  lower_reduction_clauses (gimple_omp_sections_clauses (stmt), &olist,
+			   NULL, ctx);
 
   block = make_node (BLOCK);
   new_stmt = gimple_build_bind (NULL, NULL, block);
@@ -8074,11 +8183,13 @@ lower_omp_critical (gimple_stmt_iterator
    for a lastprivate clause.  Given a loop control predicate of (V
    cond N2), we gate the clause on (!(V cond N2)).  The lowered form
    is appended to *DLIST, iterator initialization is appended to
-   *BODY_P.  */
+   *BODY_P.  *CLIST is for lastprivate(conditional:) code that needs
+   to be emitted in a critical section.  */
 
 static void
 lower_omp_for_lastprivate (struct omp_for_data *fd, gimple_seq *body_p,
-			   gimple_seq *dlist, struct omp_context *ctx)
+			   gimple_seq *dlist, gimple_seq *clist,
+			   struct omp_context *ctx)
 {
   tree clauses, cond, vinit;
   enum tree_code cond_code;
@@ -8158,7 +8269,7 @@ lower_omp_for_lastprivate (struct omp_fo
 
   clauses = gimple_omp_for_clauses (fd->for_stmt);
   stmts = NULL;
-  lower_lastprivate_clauses (clauses, cond, &stmts, ctx);
+  lower_lastprivate_clauses (clauses, cond, body_p, &stmts, clist, ctx);
   if (!gimple_seq_empty_p (stmts))
     {
       gimple_seq_add_seq (&stmts, *dlist);
@@ -8190,7 +8301,7 @@ lower_omp_for (gimple_stmt_iterator *gsi
   gomp_for *stmt = as_a <gomp_for *> (gsi_stmt (*gsi_p));
   gbind *new_stmt;
   gimple_seq omp_for_body, body, dlist, tred_ilist = NULL, tred_dlist = NULL;
-  gimple_seq cnt_list = NULL;
+  gimple_seq cnt_list = NULL, clist = NULL;
   gimple_seq oacc_head = NULL, oacc_tail = NULL;
   size_t i;
 
@@ -8308,6 +8419,9 @@ lower_omp_for (gimple_stmt_iterator *gsi
   gimple_seq_add_seq (rclauses ? &tred_ilist : &body,
 		      gimple_omp_for_pre_body (stmt));
 
+  lower_lastprivate_conditional_clauses (gimple_omp_for_clauses_ptr (stmt),
+					 ctx);
+
   lower_omp (gimple_omp_body_ptr (stmt), ctx);
 
   /* Lower the header expressions.  At this point, we can assume that
@@ -8353,7 +8467,7 @@ lower_omp_for (gimple_stmt_iterator *gsi
   if (oacc_head)
     gimple_seq_add_seq (&body, oacc_head);
 
-  lower_omp_for_lastprivate (&fd, &body, &dlist, ctx);
+  lower_omp_for_lastprivate (&fd, &body, &dlist, &clist, ctx);
 
   if (gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_FOR)
     for (tree c = gimple_omp_for_clauses (stmt); c; c = OMP_CLAUSE_CHAIN (c))
@@ -8378,13 +8492,24 @@ lower_omp_for (gimple_stmt_iterator *gsi
 							   fd.loop.v));
 
   /* After the loop, add exit clauses.  */
-  lower_reduction_clauses (gimple_omp_for_clauses (stmt), &body, ctx);
+  lower_reduction_clauses (gimple_omp_for_clauses (stmt), &body, &clist, ctx);
+
+  if (clist)
+    {
+      tree fndecl = builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_START);
+      gcall *g = gimple_build_call (fndecl, 0);
+      gimple_seq_add_stmt (&body, g);
+      gimple_seq_add_seq (&body, clist);
+      fndecl = builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_END);
+      g = gimple_build_call (fndecl, 0);
+      gimple_seq_add_stmt (&body, g);
+    }
 
   if (ctx->cancellable)
     gimple_seq_add_stmt (&body, gimple_build_label (ctx->cancel_label));
 
   gimple_seq_add_seq (&body, dlist);
-
+
   if (rclauses)
     {
       gimple_seq_add_seq (&tred_ilist, body);
@@ -9000,7 +9124,7 @@ lower_omp_taskreg (gimple_stmt_iterator
   lower_rec_input_clauses (clauses, &par_ilist, &par_olist, ctx, NULL);
   lower_omp (&par_body, ctx);
   if (gimple_code (stmt) == GIMPLE_OMP_PARALLEL)
-    lower_reduction_clauses (clauses, &par_rlist, ctx);
+    lower_reduction_clauses (clauses, &par_rlist, NULL, ctx);
 
   /* Declare all the variables created by mapping and the variables
      declared in the scope of the parallel body.  */
@@ -10189,7 +10313,8 @@ lower_omp_teams (gimple_stmt_iterator *g
   lower_rec_input_clauses (gimple_omp_teams_clauses (teams_stmt),
 			   &bind_body, &dlist, ctx, NULL);
   lower_omp (gimple_omp_body_ptr (teams_stmt), ctx);
-  lower_reduction_clauses (gimple_omp_teams_clauses (teams_stmt), &olist, ctx);
+  lower_reduction_clauses (gimple_omp_teams_clauses (teams_stmt), &olist,
+			   NULL, ctx);
   if (!gimple_omp_teams_grid_phony (teams_stmt))
     {
       gimple_seq_add_stmt (&bind_body, teams_stmt);
@@ -10498,8 +10623,28 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p
 	  default:
 	    break;
 	  }
+      goto regimplify;
+
+    case GIMPLE_ASSIGN:
+      if (ctx && ctx->lastprivate_conditional_map)
+	{
+	  tree lhs = get_base_address (gimple_assign_lhs (stmt));
+	  if (DECL_P (lhs))
+	    if (tree *v = ctx->lastprivate_conditional_map->get (lhs))
+	      {
+		tree clauses
+		  = gimple_omp_for_clauses (as_a <gomp_for *> (ctx->stmt));
+		tree c = omp_find_clause (clauses, OMP_CLAUSE__CONDTEMP_);
+		c = omp_find_clause (OMP_CLAUSE_CHAIN (c),
+				     OMP_CLAUSE__CONDTEMP_);
+		gimple *g = gimple_build_assign (*v, OMP_CLAUSE_DECL (c));
+		gsi_insert_after (gsi_p, g, GSI_SAME_STMT);
+	      }
+	}
       /* FALLTHRU */
+
     default:
+    regimplify:
       if ((ctx || task_shared_vars)
 	  && walk_gimple_op (stmt, lower_omp_regimplify_p,
 			     ctx ? NULL : &wi))
--- gcc/omp-expand.c.jj	2019-05-24 10:54:49.498681277 +0200
+++ gcc/omp-expand.c	2019-05-24 19:56:35.527290123 +0200
@@ -345,7 +345,8 @@ determine_parallel_type (struct omp_regi
 	      || ((OMP_CLAUSE_SCHEDULE_KIND (c) & OMP_CLAUSE_SCHEDULE_MASK)
 		  == OMP_CLAUSE_SCHEDULE_STATIC)
 	      || omp_find_clause (clauses, OMP_CLAUSE_ORDERED)
-	      || omp_find_clause (clauses, OMP_CLAUSE__REDUCTEMP_))
+	      || omp_find_clause (clauses, OMP_CLAUSE__REDUCTEMP_)
+	      || omp_find_clause (clauses, OMP_CLAUSE__CONDTEMP_))
 	    return;
 	}
       else if (region->inner->type == GIMPLE_OMP_SECTIONS
@@ -2679,16 +2680,17 @@ expand_omp_for_generic (struct omp_regio
 
   gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
   if (fd->ordered
-      && omp_find_clause (gimple_omp_for_clauses (gsi_stmt (gsi)),
+      && omp_find_clause (gimple_omp_for_clauses (fd->for_stmt),
 			  OMP_CLAUSE_LASTPRIVATE))
     ordered_lastprivate = false;
   tree reductions = NULL_TREE;
-  tree mem = NULL_TREE;
+  tree mem = NULL_TREE, cond_var = NULL_TREE, condtemp = NULL_TREE;
+  tree memv = NULL_TREE;
   if (sched_arg)
     {
       if (fd->have_reductemp)
 	{
-	  tree c = omp_find_clause (gimple_omp_for_clauses (gsi_stmt (gsi)),
+	  tree c = omp_find_clause (gimple_omp_for_clauses (fd->for_stmt),
 				    OMP_CLAUSE__REDUCTEMP_);
 	  reductions = OMP_CLAUSE_DECL (c);
 	  gcc_assert (TREE_CODE (reductions) == SSA_NAME);
@@ -2703,8 +2705,25 @@ expand_omp_for_generic (struct omp_regio
 	}
       else
 	reductions = null_pointer_node;
-      /* For now.  */
-      mem = null_pointer_node;
+      if (fd->lastprivate_conditional)
+	{
+	  tree c = omp_find_clause (gimple_omp_for_clauses (fd->for_stmt),
+				    OMP_CLAUSE__CONDTEMP_);
+	  condtemp = OMP_CLAUSE_DECL (c);
+	  c = omp_find_clause (OMP_CLAUSE_CHAIN (c), OMP_CLAUSE__CONDTEMP_);
+	  cond_var = OMP_CLAUSE_DECL (c);
+	  tree type = TREE_TYPE (condtemp);
+	  memv = create_tmp_var (type);
+	  TREE_ADDRESSABLE (memv) = 1;
+	  unsigned HOST_WIDE_INT sz
+	    = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (type)));
+	  sz *= fd->lastprivate_conditional;
+	  expand_omp_build_assign (&gsi, memv, build_int_cst (type, sz),
+				   false);
+	  mem = build_fold_addr_expr (memv);
+	}
+      else
+	mem = null_pointer_node;
     }
   if (fd->collapse > 1 || fd->ordered)
     {
@@ -2959,6 +2978,8 @@ expand_omp_for_generic (struct omp_regio
       gsi_insert_before (&gsi, gimple_build_assign (arr, clobber),
 			 GSI_SAME_STMT);
     }
+  if (fd->lastprivate_conditional)
+    expand_omp_build_assign (&gsi, condtemp, memv, false);
   if (fd->have_reductemp)
     {
       gimple *g = gsi_stmt (gsi);
@@ -3029,6 +3050,35 @@ expand_omp_for_generic (struct omp_regio
 				NULL_TREE, false, GSI_CONTINUE_LINKING);
   assign_stmt = gimple_build_assign (startvar, t);
   gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
+  if (cond_var)
+    {
+      tree itype = TREE_TYPE (cond_var);
+      /* For lastprivate(conditional:) itervar, we need some iteration
+	 counter that starts at unsigned non-zero and increases.
+	 Prefer as few IVs as possible, so if we can use startvar
+	 itself, use that, or startvar + constant (those would be
+	 incremented with step), and as last resort use the s0 + 1
+	 incremented by 1.  */
+      if ((fd->ordered && fd->collapse == 1)
+	  || bias
+	  || POINTER_TYPE_P (type)
+	  || TREE_CODE (fd->loop.n1) != INTEGER_CST
+	  || fd->loop.cond_code != LT_EXPR)
+	t = fold_build2 (PLUS_EXPR, itype, fold_convert (itype, istart0),
+			 build_int_cst (itype, 1));
+      else if (tree_int_cst_sgn (fd->loop.n1) == 1)
+	t = fold_convert (itype, t);
+      else
+	{
+	  tree c = fold_convert (itype, fd->loop.n1);
+	  c = fold_build2 (MINUS_EXPR, itype, build_int_cst (itype, 1), c);
+	  t = fold_build2 (PLUS_EXPR, itype, fold_convert (itype, t), c);
+	}
+      t = force_gimple_operand_gsi (&gsi, t, false,
+				    NULL_TREE, false, GSI_CONTINUE_LINKING);
+      assign_stmt = gimple_build_assign (cond_var, t);
+      gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
+    }
 
   t = iend0;
   if (fd->ordered && fd->collapse == 1)
@@ -3213,6 +3263,25 @@ expand_omp_for_generic (struct omp_regio
 	  assign_stmt = gimple_build_assign (vback, t);
 	  gsi_insert_before (&gsi, assign_stmt, GSI_SAME_STMT);
 
+	  if (cond_var)
+	    {
+	      tree itype = TREE_TYPE (cond_var);
+	      tree t2;
+	      if ((fd->ordered && fd->collapse == 1)
+		  || bias
+		  || POINTER_TYPE_P (type)
+		  || TREE_CODE (fd->loop.n1) != INTEGER_CST
+		  || fd->loop.cond_code != LT_EXPR)
+		t2 = build_int_cst (itype, 1);
+	      else
+		t2 = fold_convert (itype, fd->loop.step);
+	      t2 = fold_build2 (PLUS_EXPR, itype, cond_var, t2);
+	      t2 = force_gimple_operand_gsi (&gsi, t2, false,
+					     NULL_TREE, true, GSI_SAME_STMT);
+	      assign_stmt = gimple_build_assign (cond_var, t2);
+	      gsi_insert_before (&gsi, assign_stmt, GSI_SAME_STMT);
+	    }
+
 	  if (fd->ordered && counts[fd->collapse - 1] == NULL_TREE)
 	    {
 	      tree tem;
@@ -3465,12 +3534,13 @@ expand_omp_for_static_nochunk (struct om
   basic_block entry_bb, second_bb, third_bb, exit_bb, seq_start_bb;
   basic_block body_bb, cont_bb, collapse_bb = NULL;
   basic_block fin_bb;
-  gimple_stmt_iterator gsi;
+  gimple_stmt_iterator gsi, gsip;
   edge ep;
   bool broken_loop = region->cont == NULL;
   tree *counts = NULL;
   tree n1, n2, step;
   tree reductions = NULL_TREE;
+  tree cond_var = NULL_TREE;
 
   itype = type = TREE_TYPE (fd->loop.v);
   if (POINTER_TYPE_P (type))
@@ -3495,6 +3565,8 @@ expand_omp_for_static_nochunk (struct om
   /* Iteration space partitioning goes in ENTRY_BB.  */
   gsi = gsi_last_nondebug_bb (entry_bb);
   gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
+  gsip = gsi;
+  gsi_prev (&gsip);
 
   if (fd->collapse > 1)
     {
@@ -3524,7 +3596,7 @@ expand_omp_for_static_nochunk (struct om
       n2 = force_gimple_operand_gsi (&gsi, n2, true, NULL_TREE,
 				     true, GSI_SAME_STMT);
       gcond *cond_stmt = gimple_build_cond (fd->loop.cond_code, n1, n2,
-						 NULL_TREE, NULL_TREE);
+					    NULL_TREE, NULL_TREE);
       gsi_insert_before (&gsi, cond_stmt, GSI_SAME_STMT);
       if (walk_tree (gimple_cond_lhs_ptr (cond_stmt),
 		     expand_omp_regimplify_p, NULL, NULL)
@@ -3554,28 +3626,64 @@ expand_omp_for_static_nochunk (struct om
       gsi = gsi_last_bb (entry_bb);
     }
 
-  if (fd->have_reductemp)
+  if (fd->have_reductemp || fd->lastprivate_conditional)
     {
       tree t1 = build_int_cst (long_integer_type_node, 0);
       tree t2 = build_int_cst (long_integer_type_node, 1);
       tree t3 = build_int_cstu (long_integer_type_node,
 				(HOST_WIDE_INT_1U << 31) + 1);
       tree clauses = gimple_omp_for_clauses (fd->for_stmt);
-      clauses = omp_find_clause (clauses, OMP_CLAUSE__REDUCTEMP_);
-      reductions = OMP_CLAUSE_DECL (clauses);
-      gcc_assert (TREE_CODE (reductions) == SSA_NAME);
-      gimple *g = SSA_NAME_DEF_STMT (reductions);
-      reductions = gimple_assign_rhs1 (g);
-      OMP_CLAUSE_DECL (clauses) = reductions;
-      gimple_stmt_iterator gsi2 = gsi_for_stmt (g);
+      gimple_stmt_iterator gsi2 = gsi_none ();
+      gimple *g = NULL;
+      tree mem = null_pointer_node, memv = NULL_TREE;
+      tree condtemp = NULL_TREE;
+      if (fd->have_reductemp)
+	{
+	  tree c = omp_find_clause (clauses, OMP_CLAUSE__REDUCTEMP_);
+	  reductions = OMP_CLAUSE_DECL (c);
+	  gcc_assert (TREE_CODE (reductions) == SSA_NAME);
+	  g = SSA_NAME_DEF_STMT (reductions);
+	  reductions = gimple_assign_rhs1 (g);
+	  OMP_CLAUSE_DECL (c) = reductions;
+	  gsi2 = gsi_for_stmt (g);
+	}
+      else
+	{
+	  if (gsi_end_p (gsip))
+	    gsi2 = gsi_after_labels (region->entry);
+	  else
+	    gsi2 = gsip;
+	  reductions = null_pointer_node;
+	}
+      if (fd->lastprivate_conditional)
+	{
+	  tree c = omp_find_clause (clauses, OMP_CLAUSE__CONDTEMP_);
+	  condtemp = OMP_CLAUSE_DECL (c);
+	  c = omp_find_clause (OMP_CLAUSE_CHAIN (c), OMP_CLAUSE__CONDTEMP_);
+	  cond_var = OMP_CLAUSE_DECL (c);
+	  tree type = TREE_TYPE (condtemp);
+	  memv = create_tmp_var (type);
+	  TREE_ADDRESSABLE (memv) = 1;
+	  unsigned HOST_WIDE_INT sz
+	    = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (type)));
+	  sz *= fd->lastprivate_conditional;
+	  expand_omp_build_assign (&gsi2, memv, build_int_cst (type, sz),
+				   false);
+	  mem = build_fold_addr_expr (memv);
+	}
       tree t
 	= build_call_expr (builtin_decl_explicit (BUILT_IN_GOMP_LOOP_START),
 			   9, t1, t2, t2, t3, t1, null_pointer_node,
-			   null_pointer_node, reductions, null_pointer_node);
+			   null_pointer_node, reductions, mem);
       force_gimple_operand_gsi (&gsi2, t, true, NULL_TREE,
 				true, GSI_SAME_STMT);
-      gsi_remove (&gsi2, true);
-      release_ssa_name (gimple_assign_lhs (g));
+      if (fd->lastprivate_conditional)
+	expand_omp_build_assign (&gsi2, condtemp, memv, false);
+      if (fd->have_reductemp)
+	{
+	  gsi_remove (&gsi2, true);
+	  release_ssa_name (gimple_assign_lhs (g));
+	}
     }
   switch (gimple_omp_for_kind (fd->for_stmt))
     {
@@ -3735,6 +3843,33 @@ expand_omp_for_static_nochunk (struct om
 				NULL_TREE, false, GSI_CONTINUE_LINKING);
   assign_stmt = gimple_build_assign (startvar, t);
   gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
+  if (cond_var)
+    {
+      tree itype = TREE_TYPE (cond_var);
+      /* For lastprivate(conditional:) itervar, we need some iteration
+	 counter that starts at unsigned non-zero and increases.
+	 Prefer as few IVs as possible, so if we can use startvar
+	 itself, use that, or startvar + constant (those would be
+	 incremented with step), and as last resort use the s0 + 1
+	 incremented by 1.  */
+      if (POINTER_TYPE_P (type)
+	  || TREE_CODE (n1) != INTEGER_CST
+	  || fd->loop.cond_code != LT_EXPR)
+	t = fold_build2 (PLUS_EXPR, itype, fold_convert (itype, s0),
+			 build_int_cst (itype, 1));
+      else if (tree_int_cst_sgn (n1) == 1)
+	t = fold_convert (itype, t);
+      else
+	{
+	  tree c = fold_convert (itype, n1);
+	  c = fold_build2 (MINUS_EXPR, itype, build_int_cst (itype, 1), c);
+	  t = fold_build2 (PLUS_EXPR, itype, fold_convert (itype, t), c);
+	}
+      t = force_gimple_operand_gsi (&gsi, t, false,
+				    NULL_TREE, false, GSI_CONTINUE_LINKING);
+      assign_stmt = gimple_build_assign (cond_var, t);
+      gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
+    }
 
   t = fold_convert (itype, e0);
   t = fold_build2 (MULT_EXPR, itype, t, step);
@@ -3829,6 +3964,23 @@ expand_omp_for_static_nochunk (struct om
 	  assign_stmt = gimple_build_assign (vback, t);
 	  gsi_insert_before (&gsi, assign_stmt, GSI_SAME_STMT);
 
+	  if (cond_var)
+	    {
+	      tree itype = TREE_TYPE (cond_var);
+	      tree t2;
+	      if (POINTER_TYPE_P (type)
+		  || TREE_CODE (n1) != INTEGER_CST
+		  || fd->loop.cond_code != LT_EXPR)
+		t2 = build_int_cst (itype, 1);
+	      else
+		t2 = fold_convert (itype, step);
+	      t2 = fold_build2 (PLUS_EXPR, itype, cond_var, t2);
+	      t2 = force_gimple_operand_gsi (&gsi, t2, false,
+					     NULL_TREE, true, GSI_SAME_STMT);
+	      assign_stmt = gimple_build_assign (cond_var, t2);
+	      gsi_insert_before (&gsi, assign_stmt, GSI_SAME_STMT);
+	    }
+
 	  t = build2 (fd->loop.cond_code, boolean_type_node,
 		      DECL_P (vback) && TREE_ADDRESSABLE (vback)
 		      ? t : vback, e);
@@ -3847,7 +3999,7 @@ expand_omp_for_static_nochunk (struct om
   if (!gimple_omp_return_nowait_p (gsi_stmt (gsi)))
     {
       t = gimple_omp_return_lhs (gsi_stmt (gsi));
-      if (fd->have_reductemp)
+      if (fd->have_reductemp || fd->lastprivate_conditional)
 	{
 	  tree fn;
 	  if (t)
@@ -3858,9 +4010,10 @@ expand_omp_for_static_nochunk (struct om
 	  if (t)
 	    {
 	      gimple_call_set_lhs (g, t);
-	      gsi_insert_after (&gsi, gimple_build_assign (reductions,
-							   NOP_EXPR, t),
-				GSI_SAME_STMT);
+	      if (fd->have_reductemp)
+		gsi_insert_after (&gsi, gimple_build_assign (reductions,
+							     NOP_EXPR, t),
+				  GSI_SAME_STMT);
 	    }
 	  gsi_insert_after (&gsi, g, GSI_SAME_STMT);
 	}
@@ -3997,12 +4150,13 @@ expand_omp_for_static_chunk (struct omp_
   tree type, itype, vmain, vback, vextra;
   basic_block entry_bb, exit_bb, body_bb, seq_start_bb, iter_part_bb;
   basic_block trip_update_bb = NULL, cont_bb, collapse_bb = NULL, fin_bb;
-  gimple_stmt_iterator gsi;
+  gimple_stmt_iterator gsi, gsip;
   edge se;
   bool broken_loop = region->cont == NULL;
   tree *counts = NULL;
   tree n1, n2, step;
   tree reductions = NULL_TREE;
+  tree cond_var = NULL_TREE;
 
   itype = type = TREE_TYPE (fd->loop.v);
   if (POINTER_TYPE_P (type))
@@ -4031,6 +4185,8 @@ expand_omp_for_static_chunk (struct omp_
   /* Trip and adjustment setup goes in ENTRY_BB.  */
   gsi = gsi_last_nondebug_bb (entry_bb);
   gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR);
+  gsip = gsi;
+  gsi_prev (&gsip);
 
   if (fd->collapse > 1)
     {
@@ -4090,28 +4246,64 @@ expand_omp_for_static_chunk (struct omp_
       gsi = gsi_last_bb (entry_bb);
     }
 
-  if (fd->have_reductemp)
+  if (fd->have_reductemp || fd->lastprivate_conditional)
     {
       tree t1 = build_int_cst (long_integer_type_node, 0);
       tree t2 = build_int_cst (long_integer_type_node, 1);
       tree t3 = build_int_cstu (long_integer_type_node,
 				(HOST_WIDE_INT_1U << 31) + 1);
       tree clauses = gimple_omp_for_clauses (fd->for_stmt);
-      clauses = omp_find_clause (clauses, OMP_CLAUSE__REDUCTEMP_);
-      reductions = OMP_CLAUSE_DECL (clauses);
-      gcc_assert (TREE_CODE (reductions) == SSA_NAME);
-      gimple *g = SSA_NAME_DEF_STMT (reductions);
-      reductions = gimple_assign_rhs1 (g);
-      OMP_CLAUSE_DECL (clauses) = reductions;
-      gimple_stmt_iterator gsi2 = gsi_for_stmt (g);
+      gimple_stmt_iterator gsi2 = gsi_none ();
+      gimple *g = NULL;
+      tree mem = null_pointer_node, memv = NULL_TREE;
+      tree condtemp = NULL_TREE;
+      if (fd->have_reductemp)
+	{
+	  tree c = omp_find_clause (clauses, OMP_CLAUSE__REDUCTEMP_);
+	  reductions = OMP_CLAUSE_DECL (c);
+	  gcc_assert (TREE_CODE (reductions) == SSA_NAME);
+	  g = SSA_NAME_DEF_STMT (reductions);
+	  reductions = gimple_assign_rhs1 (g);
+	  OMP_CLAUSE_DECL (c) = reductions;
+	  gsi2 = gsi_for_stmt (g);
+	}
+      else
+	{
+	  if (gsi_end_p (gsip))
+	    gsi2 = gsi_after_labels (region->entry);
+	  else
+	    gsi2 = gsip;
+	  reductions = null_pointer_node;
+	}
+      if (fd->lastprivate_conditional)
+	{
+	  tree c = omp_find_clause (clauses, OMP_CLAUSE__CONDTEMP_);
+	  condtemp = OMP_CLAUSE_DECL (c);
+	  c = omp_find_clause (OMP_CLAUSE_CHAIN (c), OMP_CLAUSE__CONDTEMP_);
+	  cond_var = OMP_CLAUSE_DECL (c);
+	  tree type = TREE_TYPE (condtemp);
+	  memv = create_tmp_var (type);
+	  TREE_ADDRESSABLE (memv) = 1;
+	  unsigned HOST_WIDE_INT sz
+	    = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (type)));
+	  sz *= fd->lastprivate_conditional;
+	  expand_omp_build_assign (&gsi2, memv, build_int_cst (type, sz),
+				   false);
+	  mem = build_fold_addr_expr (memv);
+	}
       tree t
 	= build_call_expr (builtin_decl_explicit (BUILT_IN_GOMP_LOOP_START),
 			   9, t1, t2, t2, t3, t1, null_pointer_node,
-			   null_pointer_node, reductions, null_pointer_node);
+			   null_pointer_node, reductions, mem);
       force_gimple_operand_gsi (&gsi2, t, true, NULL_TREE,
 				true, GSI_SAME_STMT);
-      gsi_remove (&gsi2, true);
-      release_ssa_name (gimple_assign_lhs (g));
+      if (fd->lastprivate_conditional)
+	expand_omp_build_assign (&gsi2, condtemp, memv, false);
+      if (fd->have_reductemp)
+	{
+	  gsi_remove (&gsi2, true);
+	  release_ssa_name (gimple_assign_lhs (g));
+	}
     }
   switch (gimple_omp_for_kind (fd->for_stmt))
     {
@@ -4286,6 +4478,33 @@ expand_omp_for_static_chunk (struct omp_
 				NULL_TREE, false, GSI_CONTINUE_LINKING);
   assign_stmt = gimple_build_assign (startvar, t);
   gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
+  if (cond_var)
+    {
+      tree itype = TREE_TYPE (cond_var);
+      /* For lastprivate(conditional:) itervar, we need some iteration
+	 counter that starts at unsigned non-zero and increases.
+	 Prefer as few IVs as possible, so if we can use startvar
+	 itself, use that, or startvar + constant (those would be
+	 incremented with step), and as last resort use the s0 + 1
+	 incremented by 1.  */
+      if (POINTER_TYPE_P (type)
+	  || TREE_CODE (n1) != INTEGER_CST
+	  || fd->loop.cond_code != LT_EXPR)
+	t = fold_build2 (PLUS_EXPR, itype, fold_convert (itype, s0),
+			 build_int_cst (itype, 1));
+      else if (tree_int_cst_sgn (n1) == 1)
+	t = fold_convert (itype, t);
+      else
+	{
+	  tree c = fold_convert (itype, n1);
+	  c = fold_build2 (MINUS_EXPR, itype, build_int_cst (itype, 1), c);
+	  t = fold_build2 (PLUS_EXPR, itype, fold_convert (itype, t), c);
+	}
+      t = force_gimple_operand_gsi (&gsi, t, false,
+				    NULL_TREE, false, GSI_CONTINUE_LINKING);
+      assign_stmt = gimple_build_assign (cond_var, t);
+      gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
+    }
 
   t = fold_convert (itype, e0);
   t = fold_build2 (MULT_EXPR, itype, t, step);
@@ -4416,7 +4635,7 @@ expand_omp_for_static_chunk (struct omp_
   if (!gimple_omp_return_nowait_p (gsi_stmt (gsi)))
     {
       t = gimple_omp_return_lhs (gsi_stmt (gsi));
-      if (fd->have_reductemp)
+      if (fd->have_reductemp || fd->lastprivate_conditional)
 	{
 	  tree fn;
 	  if (t)
@@ -4427,9 +4646,10 @@ expand_omp_for_static_chunk (struct omp_
 	  if (t)
 	    {
 	      gimple_call_set_lhs (g, t);
-	      gsi_insert_after (&gsi, gimple_build_assign (reductions,
-							   NOP_EXPR, t),
-				GSI_SAME_STMT);
+	      if (fd->have_reductemp)
+		gsi_insert_after (&gsi, gimple_build_assign (reductions,
+							     NOP_EXPR, t),
+				  GSI_SAME_STMT);
 	    }
 	  gsi_insert_after (&gsi, g, GSI_SAME_STMT);
 	}
@@ -6043,7 +6263,7 @@ expand_omp_for (struct omp_region *regio
       else
 	start_ix = ((int)BUILT_IN_GOMP_LOOP_STATIC_START) + fn_index;
       next_ix = ((int)BUILT_IN_GOMP_LOOP_STATIC_NEXT) + fn_index;
-      if (fd.have_reductemp)
+      if (fd.have_reductemp || fd.lastprivate_conditional)
 	{
 	  if (fd.ordered)
 	    start_ix = (int)BUILT_IN_GOMP_LOOP_DOACROSS_START;
--- gcc/testsuite/c-c++-common/gomp/lastprivate-conditional-2.c.jj	2018-11-09 21:19:15.705682627 +0100
+++ gcc/testsuite/c-c++-common/gomp/lastprivate-conditional-2.c	2019-05-24 16:42:16.088941251 +0200
@@ -4,7 +4,7 @@ foo (int *p)
   int a = -1, b = -1, c = -1, d = -1, e = -1, f = -1, g = -1, h = -1;
   int i;
   #pragma omp parallel
-  #pragma omp for lastprivate (conditional: a) /* { dg-message "not supported yet" } */
+  #pragma omp for lastprivate (conditional: a)
   for (i = 0; i < 32; i++)
     if (p[i])
       a = i;
--- gcc/testsuite/c-c++-common/gomp/lastprivate-conditional-3.c.jj	2019-05-24 19:28:58.547326117 +0200
+++ gcc/testsuite/c-c++-common/gomp/lastprivate-conditional-3.c	2019-05-24 19:31:50.762517256 +0200
@@ -0,0 +1,26 @@
+void
+foo (int *p)
+{
+  int i, j, k;
+  #pragma omp parallel
+  {
+    #pragma omp for lastprivate (conditional: i)	/* { dg-warning "conditional 'lastprivate' on loop iterator 'i' ignored" } */
+    for (i = 0; i < 32; i++)
+      ;
+    #pragma omp for collapse (3) lastprivate (conditional: i)	/* { dg-warning "conditional 'lastprivate' on loop iterator 'i' ignored" } */
+    for (i = 0; i < 32; i++)
+      for (j = 0; j < 32; ++j)
+	for (k = 0; k < 2; ++k)
+	  ;
+    #pragma omp for collapse (3) lastprivate (conditional: j)	/* { dg-warning "conditional 'lastprivate' on loop iterator 'j' ignored" } */
+    for (i = 0; i < 32; i++)
+      for (j = 0; j < 32; ++j)
+	for (k = 0; k < 2; ++k)
+	  ;
+    #pragma omp for collapse (3) lastprivate (conditional: k)	/* { dg-warning "conditional 'lastprivate' on loop iterator 'k' ignored" } */
+    for (i = 0; i < 32; i++)
+      for (j = 0; j < 32; ++j)
+	for (k = 0; k < 2; ++k)
+	  ;
+  }
+}
--- libgomp/testsuite/libgomp.c-c++-common/lastprivate-conditional-1.c.jj	2019-05-24 13:04:52.250766138 +0200
+++ libgomp/testsuite/libgomp.c-c++-common/lastprivate-conditional-1.c	2019-05-24 19:27:38.782627093 +0200
@@ -0,0 +1,144 @@
+/* { dg-do run } */
+/* { dg-require-effective-target tls_runtime } */
+/* { dg-additional-options "-std=gnu99" {target c } } */
+
+#include <omp.h>
+#include <stdlib.h>
+
+int r, s, u, v, r2, s2, u2, v2, r3, s3, u3, v3;
+long long w, w2, w3, p, p2, p3;
+int *x, *x2, *x3;
+short y, y2, y3;
+int z;
+int thr1, thr2;
+#pragma omp threadprivate (thr1, thr2)
+
+void
+foo (int *a, long long int b, long long int c)
+{
+  int i;
+  long long j;
+  #pragma omp for lastprivate (conditional: u, x) nowait
+  for (i = 15; i < 64; i++)
+    {
+      if ((a[i] % 5) == 3)
+	u = i;
+      if ((a[i] % 7) == 2)
+	x = &a[i];
+    }
+  #pragma omp for nowait lastprivate (conditional: v) reduction (+:r, s) schedule (nonmonotonic: static)
+  for (i = -3; i < 119; i += 2)
+    {
+      ++s;
+      if ((a[i + 4] % 11) == 9)
+	v = i;
+      else
+	++r;
+    }
+  #pragma omp for schedule (monotonic: static) lastprivate (conditional: w) nowait
+  for (j = b; j < b + 115 * c; j += (b & 3) + 7)
+    if ((a[j] % 13) == 5)
+      w = j * 2;
+  #pragma omp for schedule (auto) lastprivate (conditional: p) collapse(3)
+  for (i = -5; i < (int) (b + 5); i += 2)
+    for (j = b + 12 + c; j > b; --j)
+      for (int k = 0; k < 5; k += c)
+	if (((((i + 5) * 13 + (13 - j)) * 5 + k) % 17) == 6)
+	  p = i * 10000 + j * 100 + k;
+
+  #pragma omp for schedule (nonmonotonic: static, 2) nowait lastprivate (conditional: u2, x2)
+  for (i = 15; i < 64; i++)
+    {
+      if ((a[i] % 5) == 3)
+	u2 = i;
+      if ((a[i] % 7) == 2)
+	x2 = &a[i];
+    }
+  #pragma omp for schedule (static, 3) lastprivate (conditional: v2) reduction (+:r2, s2)
+  for (i = -3; i < 119; i += 2)
+    {
+      ++s2;
+      if ((a[i + 4] % 11) == 9)
+	v2 = i;
+      else
+	++r2;
+    }
+  #pragma omp for lastprivate (conditional: w2) schedule (static, 1) nowait
+  for (j = b; j < b + 115 * c; j += (b & 3) + 7)
+    if ((a[j] % 13) == 5)
+      w2 = j * 2;
+  #pragma omp for schedule (static, 3) collapse (3) lastprivate (conditional: p2)
+  for (i = -5; i < (int) (b + 5); i += 2)
+    for (j = b + 12 + c; j > b; --j)
+      for (int k = 0; k < 5; k += c)
+	if (((((i + 5) * 13 + (13 - j)) * 5 + k) % 17) == 6)
+	  p2 = i * 10000 + j * 100 + k;
+
+  #pragma omp for lastprivate (conditional: u3, x3) nowait schedule (runtime)
+  for (i = 15; i < 64; i++)
+    {
+      if ((a[i] % 5) == 3)
+	u3 = i;
+      if ((a[i] % 7) == 2)
+	x3 = &a[i];
+    }
+  #pragma omp for nowait lastprivate (conditional: v3) reduction (+:r3, s3) schedule (nonmonotonic: dynamic)
+  for (i = -3; i < 119; i += 2)
+    {
+      ++s3;
+      if ((a[i + 4] % 11) == 9)
+	v3 = i;
+      else
+	++r3;
+    }
+  #pragma omp for schedule (monotonic: guided, 3) lastprivate (conditional: w3) nowait
+  for (j = b; j < b + 115 * c; j += (b & 3) + 7)
+    if ((a[j] % 13) == 5)
+      w3 = j * 2;
+  #pragma omp for schedule (dynamic, 4) lastprivate (conditional: p3) collapse(3)
+  for (i = -5; i < (int) (b + 5); i += 2)
+    for (j = b + 12 + c; j > b; --j)
+      for (int k = 0; k < 5; k += c)
+	if (((((i + 5) * 13 + (13 - j)) * 5 + k) % 17) == 6)
+	  p3 = i * 10000 + j * 100 + k;
+
+  /* Nasty testcase, verify that even a no-op assignment is accounted
+     for in lastprivate(conditional:).  */
+  #pragma omp for schedule (monotonic: static, 2) firstprivate (z) \
+		  lastprivate (conditional: z)
+  for (int k = -2000; k < 8000; ++k)
+    {
+      if (k < 3000 && (k & 3) == 1)
+	{
+	  z = k;
+	  thr1 = k;
+	}
+      else if (k == 7931)
+	{
+	  z = z;
+	  thr2 = 1;
+	}
+    }
+
+  if (thr2 && z != thr1)
+    abort ();
+}
+
+int
+main ()
+{
+  int a[128], i;
+  volatile int j = 0;
+  for (i = 0; i < 128; i++)
+    a[i] = i;
+  w = 1234;
+  #pragma omp parallel
+  foo (a, j, j + 1);
+  if (u != 63 || v != 115 || w != 140 || x != &a[58] || r != 55 || s != 61 || p != 30104)
+    abort ();
+  if (u2 != 63 || v2 != 115 || w2 != 140 || x2 != &a[58] || r2 != 55 || s2 != 61 || p2 != 30104)
+    abort ();
+  if (u3 != 63 || v3 != 115 || w3 != 140 || x3 != &a[58] || r3 != 55 || s3 != 61 || p3 != 30104)
+    abort ();
+  return 0;
+}
--- libgomp/testsuite/libgomp.c-c++-common/lastprivate-conditional-2.c.jj	2019-05-24 19:32:10.541194656 +0200
+++ libgomp/testsuite/libgomp.c-c++-common/lastprivate-conditional-2.c	2019-05-24 19:40:00.780520356 +0200
@@ -0,0 +1,171 @@
+/* { dg-do run } */
+/* { dg-require-effective-target tls_runtime } */
+/* { dg-additional-options "-std=gnu99" {target c } } */
+
+#include <omp.h>
+#include <stdlib.h>
+
+int r, s, u, v, r2, s2, u2, v2, r3, s3, u3, v3, t;
+long long w, w2, w3, p, p2, p3;
+int *x, *x2, *x3;
+short y, y2, y3;
+int z;
+int thr1, thr2;
+#pragma omp threadprivate (thr1, thr2)
+
+void
+foo (int *a, long long int b, long long int c)
+{
+  int i;
+  long long j;
+  #pragma omp for lastprivate (conditional: u, x) reduction (task, +: t)
+  for (i = 15; i < 64; i++)
+    {
+      ++t;
+      if ((a[i] % 5) == 3)
+	u = i;
+      if ((a[i] % 7) == 2)
+	x = &a[i];
+    }
+  #pragma omp for lastprivate (conditional: v) reduction (+:r, s) schedule (nonmonotonic: static) reduction (task, +: t)
+  for (i = -3; i < 119; i += 2)
+    {
+      ++s;
+      ++t;
+      if ((a[i + 4] % 11) == 9)
+	v = i;
+      else
+	++r;
+    }
+  #pragma omp for schedule (monotonic: static) lastprivate (conditional: w) reduction (task, +: t)
+  for (j = b; j < b + 115 * c; j += (b & 3) + 7)
+    {
+      if ((a[j] % 13) == 5)
+	w = j * 2;
+      ++t;
+    }
+  #pragma omp for schedule (auto) lastprivate (conditional: p) collapse(3) reduction (task, +: t)
+  for (i = -5; i < (int) (b + 5); i += 2)
+    for (j = b + 12 + c; j > b; --j)
+      for (int k = 0; k < 5; k += c)
+	{
+	  ++t;
+	  if (((((i + 5) * 13 + (13 - j)) * 5 + k) % 17) == 6)
+	    p = i * 10000 + j * 100 + k;
+	}
+
+  #pragma omp for schedule (nonmonotonic: static, 2)  reduction (task, +: t) lastprivate (conditional: u2, x2)
+  for (i = 15; i < 64; i++)
+    {
+      if ((a[i] % 5) == 3)
+	u2 = i;
+      if ((a[i] % 7) == 2)
+	x2 = &a[i];
+      t++;
+    }
+  #pragma omp for schedule (static, 3) lastprivate (conditional: v2) reduction (+:r2, s2) reduction (task, +: t)
+  for (i = -3; i < 119; i += 2)
+    {
+      ++s2;
+      if ((a[i + 4] % 11) == 9)
+	v2 = i;
+      else
+	++r2;
+      t++;
+    }
+  #pragma omp for lastprivate (conditional: w2) schedule (static, 1) reduction (task, +: t)
+  for (j = b; j < b + 115 * c; j += (b & 3) + 7)
+    {
+      if ((a[j] % 13) == 5)
+	w2 = j * 2;
+      t += 1;
+    }
+  #pragma omp for schedule (static, 3) collapse (3) reduction (task, +: t) lastprivate (conditional: p2)
+  for (i = -5; i < (int) (b + 5); i += 2)
+    for (j = b + 12 + c; j > b; --j)
+      for (int k = 0; k < 5; k += c)
+	{
+	  ++t;
+	  if (((((i + 5) * 13 + (13 - j)) * 5 + k) % 17) == 6)
+	    p2 = i * 10000 + j * 100 + k;
+	}
+
+  #pragma omp for lastprivate (conditional: u3, x3) reduction (task, +: t) schedule (runtime)
+  for (i = 15; i < 64; i++)
+    {
+      t = t + 1;
+      if ((a[i] % 5) == 3)
+	u3 = i;
+      if ((a[i] % 7) == 2)
+	x3 = &a[i];
+    }
+  #pragma omp for reduction (task, +: t) lastprivate (conditional: v3) reduction (+:r3, s3) schedule (nonmonotonic: dynamic)
+  for (i = -3; i < 119; i += 2)
+    {
+      ++s3;
+      if ((a[i + 4] % 11) == 9)
+	v3 = i;
+      else
+	++r3;
+      ++t;
+    }
+  #pragma omp for schedule (monotonic: guided, 3) lastprivate (conditional: w3) reduction (task, +: t)
+  for (j = b; j < b + 115 * c; j += (b & 3) + 7)
+    {
+      if ((a[j] % 13) == 5)
+	w3 = j * 2;
+      t++;
+    }
+  #pragma omp for schedule (dynamic, 4) lastprivate (conditional: p3) collapse(3) reduction (task, +: t)
+  for (i = -5; i < (int) (b + 5); i += 2)
+    for (j = b + 12 + c; j > b; --j)
+      for (int k = 0; k < 5; k += c)
+	{
+	  ++t;
+	  if (((((i + 5) * 13 + (13 - j)) * 5 + k) % 17) == 6)
+	    p3 = i * 10000 + j * 100 + k;
+	}
+
+  /* Nasty testcase, verify that even a no-op assignment is accounted
+     for in lastprivate(conditional:).  */
+  #pragma omp for schedule (monotonic: static, 2) firstprivate (z) \
+		  lastprivate (conditional: z) reduction (task, +: t)
+  for (int k = -2000; k < 8000; ++k)
+    {
+      t++;
+      if (k < 3000 && (k & 3) == 1)
+	{
+	  z = k;
+	  thr1 = k;
+	}
+      else if (k == 7931)
+	{
+	  z = z;
+	  thr2 = 1;
+	}
+    }
+
+  if (thr2 && z != thr1)
+    abort ();
+}
+
+int
+main ()
+{
+  int a[128], i;
+  volatile int j = 0;
+  for (i = 0; i < 128; i++)
+    a[i] = i;
+  w = 1234;
+  #pragma omp parallel
+  foo (a, j, j + 1);
+  if (u != 63 || v != 115 || w != 140 || x != &a[58] || r != 55 || s != 61 || p != 30104)
+    abort ();
+  if (u2 != 63 || v2 != 115 || w2 != 140 || x2 != &a[58] || r2 != 55 || s2 != 61 || p2 != 30104)
+    abort ();
+  if (u3 != 63 || v3 != 115 || w3 != 140 || x3 != &a[58] || r3 != 55 || s3 != 61 || p3 != 30104)
+    abort ();
+  if (t != 11356)
+    abort ();
+  return 0;
+}

	Jakub

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2019-05-24 21:34 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-24 21:34 [committed] Implement OpenMP 5.0 lastprivate(conditional:) for #pragma omp for Jakub Jelinek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).