diff mbox series

[committed] OpenMP scan for combined for simd

Message ID 20190706080927.GW815@tucnak
State New
Headers show
Series [committed] OpenMP scan for combined for simd | expand

Commit Message

Jakub Jelinek July 6, 2019, 8:09 a.m. UTC
Hi!

The following patch handles the last yet unsupported scan case,
composite #pragma omp {,parallel }for simd ... reduction(inscan, ...) ...
where we want to both parallelize and vectorize; in the first worksharing
loop use normal scan support we have for
#pragma omp simd ... reduction(inscan, ...) ...
and just store those into the per-thread array, then do the normal
worksharing loop up/down-sweep and then in the second worksharing loop
use a simple #pragma omp simd that just combines the two partial sums
and does the user's scan phase.

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

2019-07-06  Jakub Jelinek  <jakub@redhat.com>

	* omp-low.c (struct omp_context): Add for_simd_scan_phase member.
	(maybe_lookup_ctx): Add forward declaration.
	(omp_find_scan): Likewise.  Walk into body of simd if composited
	with worksharing loop.
	(scan_omp_simd_scan): New function.
	(scan_omp_1_stmt): Call it.
	(lower_rec_simd_input_clauses): Don't create rvar nor rvar2 if
	ctx->for_simd_scan_phase.
	(lower_rec_input_clauses): Do much less work for inscan reductions
	in ctx->for_simd_scan_phase is_simd regions.
	(lower_omp_scan): Set is_simd also on simd constructs composited
	with worksharing loop, unless ctx->for_simd_scan_phase.  Never emit
	a sorry message.  Don't change GIMPLE_OMP_SCAN stmts into nops and
	emit their body after in simd constructs composited with worksharing
	loop.
	(lower_omp_for_scan): Handle worksharing loop composited with simd.

	* c-c++-common/gomp/scan-4.c: Don't expect sorry message.

	* testsuite/libgomp.c/scan-11.c: New test.
	* testsuite/libgomp.c/scan-12.c: New test.
	* testsuite/libgomp.c/scan-13.c: New test.
	* testsuite/libgomp.c/scan-14.c: New test.
	* testsuite/libgomp.c/scan-15.c: New test.
	* testsuite/libgomp.c/scan-16.c: New test.
	* testsuite/libgomp.c/scan-17.c: New test.
	* testsuite/libgomp.c/scan-18.c: New test.
	* testsuite/libgomp.c++/scan-9.C: New test.
	* testsuite/libgomp.c++/scan-10.C: New test.
	* testsuite/libgomp.c++/scan-11.C: New test.
	* testsuite/libgomp.c++/scan-12.C: New test.
	* testsuite/libgomp.c++/scan-13.C: New test.
	* testsuite/libgomp.c++/scan-14.C: New test.
	* testsuite/libgomp.c++/scan-15.C: New test.
	* testsuite/libgomp.c++/scan-16.C: New test.


	Jakub

Comments

Rainer Orth July 8, 2019, 1:59 p.m. UTC | #1
Hi Jakub,

> The following patch handles the last yet unsupported scan case,
> composite #pragma omp {,parallel }for simd ... reduction(inscan, ...) ...
> where we want to both parallelize and vectorize; in the first worksharing
> loop use normal scan support we have for
> #pragma omp simd ... reduction(inscan, ...) ...
> and just store those into the per-thread array, then do the normal
> worksharing loop up/down-sweep and then in the second worksharing loop
> use a simple #pragma omp simd that just combines the two partial sums
> and does the user's scan phase.

some of the new testcases come up as UNRESOLVED on
sparc-sun-solaris2.11, both 32 and 64-bit:

UNRESOLVED: libgomp.c++/scan-13.C scan-tree-dump-times vect "vectorized [2-6] loops" 2
UNRESOLVED: libgomp.c++/scan-16.C scan-tree-dump-times vect "vectorized [2-6] loops" 2

The log shows

libgomp.c++/scan-13.C: dump file does not exist

libgomp.c++/scan-16.C: dump file does not exist

There are similar gcc-testreports results for
mips64el-unknown-linux-gnu, ia64-suse-linux-gnu, m68k-unknown-linux-gnu,
powerpc-ibm-aix7.2.0.0, hppa-unknown-linux-gnu.

While I don't see such failures on i386-pc-solaris2.11, gcc-testresults
shows a couple of cases where all libgomp.c++/scan-1[0-6].C are
unresolved on x86_64-pc-linux-gnu.

Something fishy seems to be going on here.

	Rainer
diff mbox series

Patch

--- gcc/omp-low.c.jj	2019-07-05 14:35:03.601143688 +0200
+++ gcc/omp-low.c	2019-07-05 21:23:45.813525150 +0200
@@ -147,6 +147,9 @@  struct omp_context
 
   /* True if there is nested scan context with exclusive clause.  */
   bool scan_exclusive;
+
+  /* True in the second simd loop of for simd with inscan reductions.  */
+  bool for_simd_scan_phase;
 };
 
 static splay_tree all_contexts;
@@ -2421,6 +2424,85 @@  scan_omp_simd (gimple_stmt_iterator *gsi
   scan_omp_for (stmt, outer_ctx)->simt_stmt = new_stmt;
 }
 
+static tree omp_find_scan (gimple_stmt_iterator *, bool *,
+			   struct walk_stmt_info *);
+static omp_context *maybe_lookup_ctx (gimple *);
+
+/* Duplicate #pragma omp simd, one for the scan input phase loop and one
+   for scan phase loop.  */
+
+static void
+scan_omp_simd_scan (gimple_stmt_iterator *gsi, gomp_for *stmt,
+		    omp_context *outer_ctx)
+{
+  /* The only change between inclusive and exclusive scan will be
+     within the first simd loop, so just use inclusive in the
+     worksharing loop.  */
+  outer_ctx->scan_inclusive = true;
+  tree c = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE_INCLUSIVE);
+  OMP_CLAUSE_DECL (c) = integer_zero_node;
+
+  gomp_scan *input_stmt = gimple_build_omp_scan (NULL, NULL_TREE);
+  gomp_scan *scan_stmt = gimple_build_omp_scan (NULL, c);
+  gsi_replace (gsi, input_stmt, false);
+  gimple_seq input_body = NULL;
+  gimple_seq_add_stmt (&input_body, stmt);
+  gsi_insert_after (gsi, scan_stmt, GSI_NEW_STMT);
+
+  gimple_stmt_iterator input1_gsi = gsi_none ();
+  struct walk_stmt_info wi;
+  memset (&wi, 0, sizeof (wi));
+  wi.val_only = true;
+  wi.info = (void *) &input1_gsi;
+  walk_gimple_seq_mod (gimple_omp_body_ptr (stmt), omp_find_scan, NULL, &wi);
+  gcc_assert (!gsi_end_p (input1_gsi));
+
+  gimple *input_stmt1 = gsi_stmt (input1_gsi);
+  gsi_next (&input1_gsi);
+  gimple *scan_stmt1 = gsi_stmt (input1_gsi);
+  gcc_assert (scan_stmt1 && gimple_code (scan_stmt1) == GIMPLE_OMP_SCAN);
+  c = gimple_omp_scan_clauses (as_a <gomp_scan *> (scan_stmt1));
+  if (c && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_EXCLUSIVE)
+    std::swap (input_stmt1, scan_stmt1);
+
+  gimple_seq input_body1 = gimple_omp_body (input_stmt1);
+  gimple_omp_set_body (input_stmt1, NULL);
+
+  gimple_seq scan_body = copy_gimple_seq_and_replace_locals (stmt);
+  gomp_for *new_stmt = as_a <gomp_for *> (scan_body);
+
+  gimple_omp_set_body (input_stmt1, input_body1);
+  gimple_omp_set_body (scan_stmt1, NULL);
+
+  gimple_stmt_iterator input2_gsi = gsi_none ();
+  memset (&wi, 0, sizeof (wi));
+  wi.val_only = true;
+  wi.info = (void *) &input2_gsi;
+  walk_gimple_seq_mod (gimple_omp_body_ptr (new_stmt), omp_find_scan,
+		       NULL, &wi);
+  gcc_assert (!gsi_end_p (input2_gsi));
+
+  gimple *input_stmt2 = gsi_stmt (input2_gsi);
+  gsi_next (&input2_gsi);
+  gimple *scan_stmt2 = gsi_stmt (input2_gsi);
+  gcc_assert (scan_stmt2 && gimple_code (scan_stmt2) == GIMPLE_OMP_SCAN);
+  if (c && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_EXCLUSIVE)
+    std::swap (input_stmt2, scan_stmt2);
+
+  gimple_omp_set_body (input_stmt2, NULL);
+
+  gimple_omp_set_body (input_stmt, input_body);
+  gimple_omp_set_body (scan_stmt, scan_body);
+
+  omp_context *ctx = new_omp_context (input_stmt, outer_ctx);
+  scan_omp (gimple_omp_body_ptr (input_stmt), ctx);
+
+  ctx = new_omp_context (scan_stmt, outer_ctx);
+  scan_omp (gimple_omp_body_ptr (scan_stmt), ctx);
+
+  maybe_lookup_ctx (new_stmt)->for_simd_scan_phase = true;
+}
+
 /* Scan an OpenMP sections directive.  */
 
 static void
@@ -3321,6 +3403,19 @@  scan_omp_1_stmt (gimple_stmt_iterator *g
     case GIMPLE_OMP_FOR:
       if ((gimple_omp_for_kind (as_a <gomp_for *> (stmt))
 	   == GF_OMP_FOR_KIND_SIMD)
+	  && gimple_omp_for_combined_into_p (stmt)
+	  && gimple_code (ctx->stmt) != GIMPLE_OMP_SCAN)
+	{
+	  tree clauses = gimple_omp_for_clauses (as_a <gomp_for *> (stmt));
+	  tree c = omp_find_clause (clauses, OMP_CLAUSE_REDUCTION);
+	  if (c && OMP_CLAUSE_REDUCTION_INSCAN (c) && !seen_error ())
+	    {
+	      scan_omp_simd_scan (gsi, as_a <gomp_for *> (stmt), ctx);
+	      break;
+	    }
+	}
+      if ((gimple_omp_for_kind (as_a <gomp_for *> (stmt))
+	   == GF_OMP_FOR_KIND_SIMD)
 	  && omp_maybe_offloaded_ctx (ctx)
 	  && omp_max_simt_vf ())
 	scan_omp_simd (gsi, as_a <gomp_for *> (stmt), ctx);
@@ -3757,7 +3852,7 @@  lower_rec_simd_input_clauses (tree new_v
 		     DECL_ATTRIBUTES (avar));
       gimple_add_tmp_var (avar);
       tree iavar = avar;
-      if (rvar)
+      if (rvar && !ctx->for_simd_scan_phase)
 	{
 	  /* For inscan reductions, create another array temporary,
 	     which will hold the reduced value.  */
@@ -5213,7 +5308,16 @@  lower_rec_input_clauses (tree clauses, g
 		      x = lang_hooks.decls.omp_clause_default_ctor
 				(c, unshare_expr (ivar),
 				 build_outer_var_ref (var, ctx));
-		      if (rvarp)
+		      if (rvarp && ctx->for_simd_scan_phase)
+			{
+			  if (x)
+			    gimplify_and_add (x, &llist[0]);
+			  x = lang_hooks.decls.omp_clause_dtor (c, ivar);
+			  if (x)
+			    gimplify_and_add (x, &llist[1]);
+			  break;
+			}
+		      else if (rvarp)
 			{
 			  if (x)
 			    {
@@ -5371,6 +5475,8 @@  lower_rec_input_clauses (tree clauses, g
 		  if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
 		      && OMP_CLAUSE_REDUCTION_INSCAN (c))
 		    {
+		      if (ctx->for_simd_scan_phase)
+			goto do_dtor;
 		      if (x || (!is_simd
 				&& OMP_CLAUSE_REDUCTION_OMP_ORIG_REF (c)))
 			{
@@ -5532,6 +5638,8 @@  lower_rec_input_clauses (tree clauses, g
 
 		      if (rvarp)
 			{
+			  if (ctx->for_simd_scan_phase)
+			    break;
 			  gimplify_assign (ivar, ref, &llist[0]);
 			  ref = build_outer_var_ref (var, ctx);
 			  gimplify_assign (ref, rvar, &llist[3]);
@@ -8629,11 +8737,13 @@  lower_omp_scan (gimple_stmt_iterator *gs
 
   bool input_phase = has_clauses ^ octx->scan_inclusive;
   bool is_simd = (gimple_code (octx->stmt) == GIMPLE_OMP_FOR
-		  && (gimple_omp_for_kind (octx->stmt) & GF_OMP_FOR_SIMD)
-		  && !gimple_omp_for_combined_into_p (octx->stmt));
+		  && (gimple_omp_for_kind (octx->stmt) & GF_OMP_FOR_SIMD));
   bool is_for = (gimple_code (octx->stmt) == GIMPLE_OMP_FOR
 		 && gimple_omp_for_kind (octx->stmt) == GF_OMP_FOR_KIND_FOR
 		 && !gimple_omp_for_combined_p (octx->stmt));
+  bool is_for_simd = is_simd && gimple_omp_for_combined_into_p (octx->stmt);
+  if (is_for_simd && octx->for_simd_scan_phase)
+    is_simd = false;
   if (is_simd)
     if (tree c = omp_find_clause (gimple_omp_for_clauses (octx->stmt),
 				  OMP_CLAUSE__SIMDUID_))
@@ -8866,10 +8976,7 @@  lower_omp_scan (gimple_stmt_iterator *gs
 	      }
 	  }
     }
-  else if (has_clauses)
-    sorry_at (gimple_location (stmt),
-	      "%<#pragma omp scan%> not supported yet");
-  if (!is_for)
+  if (is_simd && !is_for_simd)
     {
       gsi_insert_seq_after (gsi_p, gimple_omp_body (stmt), GSI_SAME_STMT);
       gsi_insert_seq_after (gsi_p, before, GSI_SAME_STMT);
@@ -9115,6 +9222,12 @@  omp_find_scan (gimple_stmt_iterator *gsi
     {
     WALK_SUBSTMTS;
 
+    case GIMPLE_OMP_FOR:
+      if ((gimple_omp_for_kind (stmt) & GF_OMP_FOR_SIMD)
+	  && gimple_omp_for_combined_into_p (stmt))
+	*handled_ops_p = false;
+      break;
+
     case GIMPLE_OMP_SCAN:
       *(gimple_stmt_iterator *) (wi->info) = *gsi_p;
       return integer_zero_node;
@@ -9255,6 +9368,7 @@  static void
 lower_omp_for_scan (gimple_seq *body_p, gimple_seq *dlist, gomp_for *stmt,
 		    struct omp_for_data *fd, omp_context *ctx)
 {
+  bool is_for_simd = gimple_omp_for_combined_p (stmt);
   gcc_assert (ctx->scan_inclusive || ctx->scan_exclusive);
 
   gimple_seq body = gimple_omp_body (stmt);
@@ -9299,6 +9413,45 @@  lower_omp_for_scan (gimple_seq *body_p,
   gcc_assert (scan_stmt2 && gimple_code (scan_stmt2) == GIMPLE_OMP_SCAN);
   gimple_omp_set_body (scan_stmt2, scan_body);
 
+  gimple_stmt_iterator input3_gsi = gsi_none ();
+  gimple_stmt_iterator scan3_gsi = gsi_none ();
+  gimple_stmt_iterator input4_gsi = gsi_none ();
+  gimple_stmt_iterator scan4_gsi = gsi_none ();
+  gimple *input_stmt3 = NULL, *scan_stmt3 = NULL;
+  gimple *input_stmt4 = NULL, *scan_stmt4 = NULL;
+  omp_context *input_simd_ctx = NULL, *scan_simd_ctx = NULL;
+  if (is_for_simd)
+    {
+      memset (&wi, 0, sizeof (wi));
+      wi.val_only = true;
+      wi.info = (void *) &input3_gsi;
+      walk_gimple_seq_mod (&input_body, omp_find_scan, NULL, &wi);
+      gcc_assert (!gsi_end_p (input3_gsi));
+
+      input_stmt3 = gsi_stmt (input3_gsi);
+      gsi = input3_gsi;
+      gsi_next (&gsi);
+      scan3_gsi = gsi;
+      scan_stmt3 = gsi_stmt (gsi);
+      gcc_assert (scan_stmt3 && gimple_code (scan_stmt3) == GIMPLE_OMP_SCAN);
+
+      memset (&wi, 0, sizeof (wi));
+      wi.val_only = true;
+      wi.info = (void *) &input4_gsi;
+      walk_gimple_seq_mod (&scan_body, omp_find_scan, NULL, &wi);
+      gcc_assert (!gsi_end_p (input4_gsi));
+
+      input_stmt4 = gsi_stmt (input4_gsi);
+      gsi = input4_gsi;
+      gsi_next (&gsi);
+      scan4_gsi = gsi;
+      scan_stmt4 = gsi_stmt (gsi);
+      gcc_assert (scan_stmt4 && gimple_code (scan_stmt4) == GIMPLE_OMP_SCAN);
+
+      input_simd_ctx = maybe_lookup_ctx (input_stmt3)->outer;
+      scan_simd_ctx = maybe_lookup_ctx (input_stmt4)->outer;
+    }
+
   tree num_threads = create_tmp_var (integer_type_node);
   tree thread_num = create_tmp_var (integer_type_node);
   tree nthreads_decl = builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_THREADS);
@@ -9390,6 +9543,18 @@  lower_omp_for_scan (gimple_seq *body_p,
 	x = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (rprivb), rprivb, x);
 	tree rprivb_ref = build_simple_mem_ref_loc (clause_loc, x);
 
+	tree var4 = is_for_simd ? new_var : var2;
+	tree var5 = NULL_TREE, var6 = NULL_TREE;
+	if (is_for_simd)
+	  {
+	    var5 = lookup_decl (var, input_simd_ctx);
+	    var6 = lookup_decl (var, scan_simd_ctx);
+	    if (new_vard != new_var)
+	      {
+		var5 = build_simple_mem_ref_loc (clause_loc, var5);
+		var6 = build_simple_mem_ref_loc (clause_loc, var6);
+	      }
+	  }
 	if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
 	  {
 	    tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c);
@@ -9401,16 +9566,19 @@  lower_omp_for_scan (gimple_seq *body_p,
 	      gimplify_and_add (x, &clist);
 
 	    x = build_outer_var_ref (var, ctx);
-	    x = lang_hooks.decls.omp_clause_assign_op (c, var2, x);
+	    x = lang_hooks.decls.omp_clause_assign_op (c, unshare_expr (var4),
+						       x);
 	    gimplify_and_add (x, &thr01_list);
 
 	    tree y = (DECL_HAS_VALUE_EXPR_P (new_vard)
 		      ? DECL_VALUE_EXPR (new_vard) : NULL_TREE);
 	    if (var3)
 	      {
-		x = lang_hooks.decls.omp_clause_assign_op (c, var2, var3);
+		x = unshare_expr (var4);
+		x = lang_hooks.decls.omp_clause_assign_op (c, x, var3);
 		gimplify_and_add (x, &thrn1_list);
-		x = lang_hooks.decls.omp_clause_assign_op (c, var2, var3);
+		x = unshare_expr (var4);
+		x = lang_hooks.decls.omp_clause_assign_op (c, x, var3);
 		gimplify_and_add (x, &thr02_list);
 	      }
 	    else if (OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c))
@@ -9418,11 +9586,13 @@  lower_omp_for_scan (gimple_seq *body_p,
 		/* Otherwise, assign to it the identity element.  */
 		gimple_seq tseq = OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c);
 		tseq = copy_gimple_seq_and_replace_locals (tseq);
-
-		if (new_vard != new_var)
-		  val = build_fold_addr_expr_loc (clause_loc, val);
-		SET_DECL_VALUE_EXPR (new_vard, val);
-		DECL_HAS_VALUE_EXPR_P (new_vard) = 1;
+		if (!is_for_simd)
+		  {
+		    if (new_vard != new_var)
+		      val = build_fold_addr_expr_loc (clause_loc, val);
+		    SET_DECL_VALUE_EXPR (new_vard, val);
+		    DECL_HAS_VALUE_EXPR_P (new_vard) = 1;
+		  }
 		SET_DECL_VALUE_EXPR (placeholder, error_mark_node);
 		DECL_HAS_VALUE_EXPR_P (placeholder) = 1;
 		lower_omp (&tseq, ctx);
@@ -9442,47 +9612,64 @@  lower_omp_for_scan (gimple_seq *body_p,
 		  }
 	      }
 
-	    x = lang_hooks.decls.omp_clause_assign_op (c, var2, rprivam1_ref);
+	    x = unshare_expr (var4);
+	    x = lang_hooks.decls.omp_clause_assign_op (c, x, rprivam1_ref);
 	    gimplify_and_add (x, &thrn2_list);
 
-	    if (ctx->scan_exclusive)
+	    if (is_for_simd)
 	      {
 		x = unshare_expr (rprivb_ref);
-		x = lang_hooks.decls.omp_clause_assign_op (c, x, var2);
+		x = lang_hooks.decls.omp_clause_assign_op (c, x, var5);
 		gimplify_and_add (x, &scan1_list);
 	      }
+	    else
+	      {
+		if (ctx->scan_exclusive)
+		  {
+		    x = unshare_expr (rprivb_ref);
+		    x = lang_hooks.decls.omp_clause_assign_op (c, x, var2);
+		    gimplify_and_add (x, &scan1_list);
+		  }
 
-	    gimple_seq tseq = OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c);
-	    tseq = copy_gimple_seq_and_replace_locals (tseq);
-	    SET_DECL_VALUE_EXPR (placeholder, var2);
-	    DECL_HAS_VALUE_EXPR_P (placeholder) = 1;
-	    lower_omp (&tseq, ctx);
-	    gimple_seq_add_seq (&scan1_list, tseq);
+		gimple_seq tseq = OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c);
+		tseq = copy_gimple_seq_and_replace_locals (tseq);
+		SET_DECL_VALUE_EXPR (placeholder, var2);
+		DECL_HAS_VALUE_EXPR_P (placeholder) = 1;
+		lower_omp (&tseq, ctx);
+		gimple_seq_add_seq (&scan1_list, tseq);
 
-	    if (ctx->scan_inclusive)
-	      {
-		x = unshare_expr (rprivb_ref);
-		x = lang_hooks.decls.omp_clause_assign_op (c, x, var2);
-		gimplify_and_add (x, &scan1_list);
+		if (ctx->scan_inclusive)
+		  {
+		    x = unshare_expr (rprivb_ref);
+		    x = lang_hooks.decls.omp_clause_assign_op (c, x, var2);
+		    gimplify_and_add (x, &scan1_list);
+		  }
 	      }
 
 	    x = unshare_expr (rpriva_ref);
-	    x = lang_hooks.decls.omp_clause_assign_op (c, x, var2);
+	    x = lang_hooks.decls.omp_clause_assign_op (c, x,
+						       unshare_expr (var4));
 	    gimplify_and_add (x, &mdlist);
 
-	    x = unshare_expr (new_var);
-	    x = lang_hooks.decls.omp_clause_assign_op (c, x, var2);
+	    x = unshare_expr (is_for_simd ? var6 : new_var);
+	    x = lang_hooks.decls.omp_clause_assign_op (c, x, var4);
 	    gimplify_and_add (x, &input2_list);
 
 	    val = rprivb_ref;
 	    if (new_vard != new_var)
 	      val = build_fold_addr_expr_loc (clause_loc, val);
 
-	    tseq = OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c);
+	    gimple_seq tseq = OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c);
 	    tseq = copy_gimple_seq_and_replace_locals (tseq);
 	    SET_DECL_VALUE_EXPR (new_vard, val);
 	    DECL_HAS_VALUE_EXPR_P (new_vard) = 1;
-	    DECL_HAS_VALUE_EXPR_P (placeholder) = 0;
+	    if (is_for_simd)
+	      {
+		SET_DECL_VALUE_EXPR (placeholder, var6);
+		DECL_HAS_VALUE_EXPR_P (placeholder) = 1;
+	      }
+	    else
+	      DECL_HAS_VALUE_EXPR_P (placeholder) = 0;
 	    lower_omp (&tseq, ctx);
 	    if (y)
 	      SET_DECL_VALUE_EXPR (new_vard, y);
@@ -9491,9 +9678,12 @@  lower_omp_for_scan (gimple_seq *body_p,
 		DECL_HAS_VALUE_EXPR_P (new_vard) = 0;
 		SET_DECL_VALUE_EXPR (new_vard, NULL_TREE);
 	      }
-	    SET_DECL_VALUE_EXPR (placeholder, new_var);
-	    DECL_HAS_VALUE_EXPR_P (placeholder) = 1;
-	    lower_omp (&tseq, ctx);
+	    if (!is_for_simd)
+	      {
+		SET_DECL_VALUE_EXPR (placeholder, new_var);
+		DECL_HAS_VALUE_EXPR_P (placeholder) = 1;
+		lower_omp (&tseq, ctx);
+	      }
 	    gimple_seq_add_seq (&input2_list, tseq);
 
 	    x = build_outer_var_ref (var, ctx);
@@ -9532,29 +9722,38 @@  lower_omp_for_scan (gimple_seq *body_p,
 	else
 	  {
 	    x = build_outer_var_ref (var, ctx);
-	    gimplify_assign (var2, x, &thr01_list);
+	    gimplify_assign (unshare_expr (var4), x, &thr01_list);
 
 	    x = omp_reduction_init (c, TREE_TYPE (new_var));
-	    gimplify_assign (var2, unshare_expr (x), &thrn1_list);
-	    gimplify_assign (var2, x, &thr02_list);
+	    gimplify_assign (unshare_expr (var4), unshare_expr (x),
+			     &thrn1_list);
+	    gimplify_assign (unshare_expr (var4), x, &thr02_list);
 
-	    gimplify_assign (var2, rprivam1_ref, &thrn2_list);
+	    gimplify_assign (unshare_expr (var4), rprivam1_ref, &thrn2_list);
 
 	    enum tree_code code = OMP_CLAUSE_REDUCTION_CODE (c);
 	    if (code == MINUS_EXPR)
 	      code = PLUS_EXPR;
 
-	    if (ctx->scan_exclusive)
-	      gimplify_assign (unshare_expr (rprivb_ref), var2, &scan1_list);
-	    x = build2 (code, TREE_TYPE (new_var), var2, new_var);
-	    gimplify_assign (var2, x, &scan1_list);
-	    if (ctx->scan_inclusive)
-	      gimplify_assign (unshare_expr (rprivb_ref), var2, &scan1_list);
+	    if (is_for_simd)
+	      gimplify_assign (unshare_expr (rprivb_ref), var5, &scan1_list);
+	    else
+	      {
+		if (ctx->scan_exclusive)
+		  gimplify_assign (unshare_expr (rprivb_ref), var2,
+				   &scan1_list);
+		x = build2 (code, TREE_TYPE (new_var), var2, new_var);
+		gimplify_assign (var2, x, &scan1_list);
+		if (ctx->scan_inclusive)
+		  gimplify_assign (unshare_expr (rprivb_ref), var2,
+				   &scan1_list);
+	      }
 
-	    gimplify_assign (unshare_expr (rpriva_ref), var2, &mdlist);
+	    gimplify_assign (unshare_expr (rpriva_ref), unshare_expr (var4),
+			     &mdlist);
 
-	    x = build2 (code, TREE_TYPE (new_var), var2, rprivb_ref);
-	    gimplify_assign (new_var, x, &input2_list);
+	    x = build2 (code, TREE_TYPE (new_var), var4, rprivb_ref);
+	    gimplify_assign (is_for_simd ? var6 : new_var, x, &input2_list);
 
 	    gimplify_assign (build_outer_var_ref (var, ctx), rpriva_ref,
 			     &last_list);
@@ -9568,7 +9767,8 @@  lower_omp_for_scan (gimple_seq *body_p,
   g = gimple_build_assign (ivar, PLUS_EXPR, ivar, size_one_node);
   gimple_seq_add_stmt (&scan1_list, g);
   g = gimple_build_assign (ivar, PLUS_EXPR, ivar, size_one_node);
-  gimple_seq_add_stmt (gimple_omp_body_ptr (scan_stmt2), g);
+  gimple_seq_add_stmt (gimple_omp_body_ptr (is_for_simd
+					    ? scan_stmt4 : scan_stmt2), g);
 
   tree controlb = create_tmp_var (boolean_type_node);
   tree controlp = create_tmp_var (ptr_type_node);
@@ -9598,8 +9798,29 @@  lower_omp_for_scan (gimple_seq *body_p,
   *cp2 = gimple_omp_for_clauses (new_stmt);
   gimple_omp_for_set_clauses (new_stmt, new_clauses2);
 
-  gimple_omp_set_body (scan_stmt1, scan1_list);
-  gimple_omp_set_body (input_stmt2, input2_list);
+  if (is_for_simd)
+    {
+      gimple_seq_add_seq (gimple_omp_body_ptr (scan_stmt3), scan1_list);
+      gimple_seq_add_seq (gimple_omp_body_ptr (input_stmt4), input2_list);
+
+      gsi_insert_seq_after (&input3_gsi, gimple_omp_body (input_stmt3),
+			    GSI_SAME_STMT);
+      gsi_remove (&input3_gsi, true);
+      gsi_insert_seq_after (&scan3_gsi, gimple_omp_body (scan_stmt3),
+			    GSI_SAME_STMT);
+      gsi_remove (&scan3_gsi, true);
+      gsi_insert_seq_after (&input4_gsi, gimple_omp_body (input_stmt4),
+			    GSI_SAME_STMT);
+      gsi_remove (&input4_gsi, true);
+      gsi_insert_seq_after (&scan4_gsi, gimple_omp_body (scan_stmt4),
+			    GSI_SAME_STMT);
+      gsi_remove (&scan4_gsi, true);
+    }
+  else
+    {
+      gimple_omp_set_body (scan_stmt1, scan1_list);
+      gimple_omp_set_body (input_stmt2, input2_list);
+    }
 
   gsi_insert_seq_after (&input1_gsi, gimple_omp_body (input_stmt1),
 			GSI_SAME_STMT);
--- gcc/testsuite/c-c++-common/gomp/scan-4.c.jj	2019-06-10 14:18:17.461525669 +0200
+++ gcc/testsuite/c-c++-common/gomp/scan-4.c	2019-07-05 22:52:55.519309033 +0200
@@ -8,7 +8,7 @@  f1 (int *c, int *d)
   for (i = 0; i < 64; i++)
     {
       d[i] = a;
-      #pragma omp scan exclusive (a)		/* { dg-message "sorry, unimplemented: '#pragma omp scan' not supported yet" } */
+      #pragma omp scan exclusive (a)
       a += c[i];
     }
 }
--- libgomp/testsuite/libgomp.c/scan-11.c.jj	2019-07-05 14:40:21.722984327 +0200
+++ libgomp/testsuite/libgomp.c/scan-11.c	2019-07-05 15:12:13.186277994 +0200
@@ -0,0 +1,118 @@ 
+/* { dg-require-effective-target size32plus } */
+/* { dg-additional-options "-O2 -fopenmp -fdump-tree-vect-details" } */
+/* { dg-additional-options "-mavx" { target avx_runtime } } */
+/* { dg-final { scan-tree-dump-times "vectorized \[2-6] loops" 2 "vect" { target sse2_runtime } } } */
+
+extern void abort (void);
+int r, a[1024], b[1024];
+
+__attribute__((noipa)) void
+foo (int *a, int *b)
+{
+  #pragma omp for simd reduction (inscan, +:r)
+  for (int i = 0; i < 1024; i++)
+    {
+      r += a[i];
+      #pragma omp scan inclusive(r)
+      b[i] = r;
+    }
+}
+
+__attribute__((noipa)) int
+bar (void)
+{
+  int s = 0;
+  #pragma omp parallel
+  #pragma omp for simd reduction (inscan, +:s) if (0)
+  for (int i = 0; i < 1024; i++)
+    {
+      s += 2 * a[i];
+      #pragma omp scan inclusive(s)
+      b[i] = s;
+    }
+  return s;
+}
+
+__attribute__((noipa)) void
+baz (int *a, int *b)
+{
+  #pragma omp parallel for simd reduction (inscan, +:r) simdlen(1)
+  for (int i = 0; i < 1024; i++)
+    {
+      r += a[i];
+      #pragma omp scan inclusive(r)
+      b[i] = r;
+    }
+}
+
+__attribute__((noipa)) int
+qux (void)
+{
+  int s = 0;
+  #pragma omp parallel for simd reduction (inscan, +:s)
+  for (int i = 0; i < 1024; i++)
+    {
+      s += 2 * a[i];
+      #pragma omp scan inclusive(s)
+      b[i] = s;
+    }
+  return s;
+}
+
+int
+main ()
+{
+  int s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      a[i] = i;
+      b[i] = -1;
+      asm ("" : "+g" (i));
+    }
+  #pragma omp parallel
+  foo (a, b);
+  if (r != 1024 * 1023 / 2)
+    abort ();
+  for (int i = 0; i < 1024; ++i)
+    {
+      s += i;
+      if (b[i] != s)
+	abort ();
+      else
+	b[i] = 25;
+    }
+  if (bar () != 1024 * 1023)
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      s += 2 * i;
+      if (b[i] != s)
+	abort ();
+      else
+	b[i] = -1;
+    }
+  r = 0;
+  baz (a, b);
+  if (r != 1024 * 1023 / 2)
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      s += i;
+      if (b[i] != s)
+	abort ();
+      else
+	b[i] = -25;
+    }
+  if (qux () != 1024 * 1023)
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      s += 2 * i;
+      if (b[i] != s)
+	abort ();
+    }
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/scan-12.c.jj	2019-07-05 14:40:21.725984279 +0200
+++ libgomp/testsuite/libgomp.c/scan-12.c	2019-07-05 15:28:42.545448409 +0200
@@ -0,0 +1,120 @@ 
+/* { dg-require-effective-target size32plus } */
+/* { dg-additional-options "-O2 -fopenmp -fdump-tree-vect-details" } */
+/* { dg-additional-options "-mavx" { target avx_runtime } } */
+/* { dg-final { scan-tree-dump-times "vectorized \[2-6] loops" 2 "vect" { target sse2_runtime } } } */
+
+extern void abort (void);
+int r, a[1024], b[1024];
+
+#pragma omp declare reduction (foo: int: omp_out += omp_in) initializer (omp_priv = 0)
+
+__attribute__((noipa)) void
+foo (int *a, int *b)
+{
+  #pragma omp for simd reduction (inscan, foo:r) simdlen (1)
+  for (int i = 0; i < 1024; i++)
+    {
+      r += a[i];
+      #pragma omp scan inclusive(r)
+      b[i] = r;
+    }
+}
+
+__attribute__((noipa)) int
+bar (void)
+{
+  int s = 0;
+  #pragma omp parallel
+  #pragma omp for simd reduction (inscan, foo:s)
+  for (int i = 0; i < 1024; i++)
+    {
+      s += 2 * a[i];
+      #pragma omp scan inclusive(s)
+      b[i] = s;
+    }
+  return s;
+}
+
+__attribute__((noipa)) void
+baz (int *a, int *b)
+{
+  #pragma omp parallel for simd reduction (inscan, foo:r)
+  for (int i = 0; i < 1024; i++)
+    {
+      r += a[i];
+      #pragma omp scan inclusive(r)
+      b[i] = r;
+    }
+}
+
+__attribute__((noipa)) int
+qux (void)
+{
+  int s = 0;
+  #pragma omp parallel for simd if (simd: 0) reduction (inscan, foo:s)
+  for (int i = 0; i < 1024; i++)
+    {
+      s += 2 * a[i];
+      #pragma omp scan inclusive(s)
+      b[i] = s;
+    }
+  return s;
+}
+
+int
+main ()
+{
+  int s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      a[i] = i;
+      b[i] = -1;
+      asm ("" : "+g" (i));
+    }
+  #pragma omp parallel
+  foo (a, b);
+  if (r != 1024 * 1023 / 2)
+    abort ();
+  for (int i = 0; i < 1024; ++i)
+    {
+      s += i;
+      if (b[i] != s)
+	abort ();
+      else
+	b[i] = 25;
+    }
+  if (bar () != 1024 * 1023)
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      s += 2 * i;
+      if (b[i] != s)
+	abort ();
+      else
+	b[i] = -1;
+    }
+  r = 0;
+  baz (a, b);
+  if (r != 1024 * 1023 / 2)
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      s += i;
+      if (b[i] != s)
+	abort ();
+      else
+	b[i] = -25;
+    }
+  if (qux () != 1024 * 1023)
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      s += 2 * i;
+      if (b[i] != s)
+	abort ();
+    }
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/scan-13.c.jj	2019-07-05 14:40:21.727984246 +0200
+++ libgomp/testsuite/libgomp.c/scan-13.c	2019-07-05 15:49:08.828174559 +0200
@@ -0,0 +1,91 @@ 
+/* { dg-require-effective-target size32plus } */
+/* { dg-additional-options "-O2 -fopenmp -fdump-tree-vect-details" } */
+/* { dg-additional-options "-mavx" { target avx_runtime } } */
+/* { dg-final { scan-tree-dump-times "vectorized \[2-6] loops" 2 "vect" { target sse2_runtime } } } */
+
+extern void abort (void);
+float r = 1.0f, a[1024], b[1024];
+
+__attribute__((noipa)) void
+foo (float *a, float *b)
+{
+  #pragma omp for simd reduction (inscan, *:r)
+  for (int i = 0; i < 1024; i++)
+    {
+      r *= a[i];
+      #pragma omp scan inclusive(r)
+      b[i] = r;
+    }
+}
+
+__attribute__((noipa)) float
+bar (void)
+{
+  float s = -__builtin_inff ();
+  #pragma omp parallel for simd reduction (inscan, max:s)
+  for (int i = 0; i < 1024; i++)
+    {
+      s = s > a[i] ? s : a[i];
+      #pragma omp scan inclusive(s)
+      b[i] = s;
+    }
+  return s;
+}
+
+int
+main ()
+{
+  float s = 1.0f;
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (i < 80)
+	a[i] = (i & 1) ? 0.25f : 0.5f;
+      else if (i < 200)
+	a[i] = (i % 3) == 0 ? 2.0f : (i % 3) == 1 ? 4.0f : 1.0f;
+      else if (i < 280)
+	a[i] = (i & 1) ? 0.25f : 0.5f;
+      else if (i < 380)
+	a[i] = (i % 3) == 0 ? 2.0f : (i % 3) == 1 ? 4.0f : 1.0f;
+      else
+	switch (i % 6)
+	  {
+	  case 0: a[i] = 0.25f; break;
+	  case 1: a[i] = 2.0f; break;
+	  case 2: a[i] = -1.0f; break;
+	  case 3: a[i] = -4.0f; break;
+	  case 4: a[i] = 0.5f; break;
+	  case 5: a[i] = 1.0f; break;
+	  default: a[i] = 0.0f; break;
+	  }
+      b[i] = -19.0f;
+      asm ("" : "+g" (i));
+    }
+  #pragma omp parallel
+  foo (a, b);
+  if (r * 16384.0f != 0.125f)
+    abort ();
+  float m = -175.25f;
+  for (int i = 0; i < 1024; ++i)
+    {
+      s *= a[i];
+      if (b[i] != s)
+	abort ();
+      else
+	{
+	  a[i] = m - ((i % 3) == 1 ? 2.0f : (i % 3) == 2 ? 4.0f : 0.0f);
+	  b[i] = -231.75f;
+	  m += 0.75f;
+	}
+    }
+  if (bar () != 592.0f)
+    abort ();
+  s = -__builtin_inff ();
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (s < a[i])
+	s = a[i];
+      if (b[i] != s)
+	abort ();
+    }
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/scan-14.c.jj	2019-07-05 14:40:21.728984230 +0200
+++ libgomp/testsuite/libgomp.c/scan-14.c	2019-07-05 15:51:34.982860711 +0200
@@ -0,0 +1,182 @@ 
+/* { dg-require-effective-target size32plus } */
+/* { dg-additional-options "-O2 -fopenmp -fdump-tree-vect-details" } */
+/* { dg-additional-options "-mavx" { target avx_runtime } } */
+/* { dg-final { scan-tree-dump-times "vectorized \[2-6] loops" 2 "vect" { target sse2_runtime } } } */
+
+extern void abort (void);
+int r, a[1024], b[1024];
+unsigned short r2, b2[1024];
+unsigned char r3, b3[1024];
+
+__attribute__((noipa)) void
+foo (int *a, int *b, unsigned short *b2, unsigned char *b3)
+{
+  #pragma omp for simd reduction (inscan, +:r, r2, r3) if (simd:0)
+  for (int i = 0; i < 1024; i++)
+    {
+      { r += a[i]; r2 += a[i]; r3 += a[i]; }
+      #pragma omp scan inclusive(r, r2, r3)
+      {
+	b[i] = r;
+	b2[i] = r2;
+	b3[i] = r3;
+      }
+    }
+}
+
+__attribute__((noipa)) int
+bar (unsigned short *s2p, unsigned char *s3p)
+{
+  int s = 0;
+  unsigned short s2 = 0;
+  unsigned char s3 = 0;
+  #pragma omp parallel
+  #pragma omp for simd reduction (inscan, +:s, s2, s3) simdlen (1)
+  for (int i = 0; i < 1024; i++)
+    {
+      {
+	s += 2 * a[i];
+	s2 += 2 * a[i];
+	s3 += 2 * a[i];
+      }
+      #pragma omp scan inclusive(s, s2, s3)
+      { b[i] = s; b2[i] = s2; b3[i] = s3; }
+    }
+  *s2p = s2;
+  *s3p = s3;
+  return s;
+}
+
+__attribute__((noipa)) void
+baz (int *a, int *b, unsigned short *b2, unsigned char *b3)
+{
+  #pragma omp parallel for simd reduction (inscan, +:r, r2, r3)
+  for (int i = 0; i < 1024; i++)
+    {
+      {
+	r += a[i];
+	r2 += a[i];
+	r3 += a[i];
+      }
+      #pragma omp scan inclusive(r, r2, r3)
+      {
+	b[i] = r;
+	b2[i] = r2;
+	b3[i] = r3;
+      }
+    }
+}
+
+__attribute__((noipa)) int
+qux (unsigned short *s2p, unsigned char *s3p)
+{
+  int s = 0;
+  unsigned short s2 = 0;
+  unsigned char s3 = 0;
+  #pragma omp parallel for simd reduction (inscan, +:s, s2, s3)
+  for (int i = 0; i < 1024; i++)
+    {
+      { s += 2 * a[i]; s2 += 2 * a[i]; s3 += 2 * a[i]; }
+      #pragma omp scan inclusive(s, s2, s3)
+      { b[i] = s; b2[i] = s2; b3[i] = s3; }
+    }
+  *s2p = s2;
+  *s3p = s3;
+  return s;
+}
+
+int
+main ()
+{
+  int s = 0;
+  unsigned short s2;
+  unsigned char s3;
+  for (int i = 0; i < 1024; ++i)
+    {
+      a[i] = i;
+      b[i] = -1;
+      b2[i] = -1;
+      b3[i] = -1;
+      asm ("" : "+g" (i));
+    }
+  #pragma omp parallel
+  foo (a, b, b2, b3);
+  if (r != 1024 * 1023 / 2
+      || r2 != (unsigned short) r
+      || r3 != (unsigned char) r)
+    abort ();
+  for (int i = 0; i < 1024; ++i)
+    {
+      s += i;
+      if (b[i] != s
+	  || b2[i] != (unsigned short) s
+	  || b3[i] != (unsigned char) s)
+	abort ();
+      else
+	{
+	  b[i] = 25;
+	  b2[i] = 24;
+	  b3[i] = 26;
+	}
+    }
+  if (bar (&s2, &s3) != 1024 * 1023)
+    abort ();
+  if (s2 != (unsigned short) (1024 * 1023)
+      || s3 != (unsigned char) (1024 * 1023))
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      s += 2 * i;
+      if (b[i] != s
+	  || b2[i] != (unsigned short) s
+	  || b3[i] != (unsigned char) s)
+	abort ();
+      else
+	{
+	  b[i] = -1;
+	  b2[i] = -1;
+	  b3[i] = -1;
+	}
+    }
+  r = 0;
+  r2 = 0;
+  r3 = 0;
+  baz (a, b, b2, b3);
+  if (r != 1024 * 1023 / 2
+      || r2 != (unsigned short) r
+      || r3 != (unsigned char) r)
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      s += i;
+      if (b[i] != s
+	  || b2[i] != (unsigned short) s
+	  || b3[i] != (unsigned char) s)
+	abort ();
+      else
+	{
+	  b[i] = 25;
+	  b2[i] = 24;
+	  b3[i] = 26;
+	}
+    }
+  s2 = 0;
+  s3 = 0;
+  if (qux (&s2, &s3) != 1024 * 1023)
+    abort ();
+  if (s2 != (unsigned short) (1024 * 1023)
+      || s3 != (unsigned char) (1024 * 1023))
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      s += 2 * i;
+      if (b[i] != s
+	  || b2[i] != (unsigned short) s
+	  || b3[i] != (unsigned char) s)
+	abort ();
+    }
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/scan-15.c.jj	2019-07-05 14:40:21.730984198 +0200
+++ libgomp/testsuite/libgomp.c/scan-15.c	2019-07-05 15:52:34.802918447 +0200
@@ -0,0 +1,118 @@ 
+/* { dg-require-effective-target size32plus } */
+/* { dg-additional-options "-O2 -fopenmp -fdump-tree-vect-details" } */
+/* { dg-additional-options "-mavx" { target avx_runtime } } */
+/* { dg-final { scan-tree-dump-times "vectorized \[2-6] loops" 2 "vect" { target sse2_runtime } } } */
+
+extern void abort (void);
+int r, a[1024], b[1024];
+
+__attribute__((noipa)) void
+foo (int *a, int *b)
+{
+  #pragma omp for simd reduction (inscan, +:r)
+  for (int i = 0; i < 1024; i++)
+    {
+      b[i] = r;
+      #pragma omp scan exclusive(r)
+      r += a[i];
+    }
+}
+
+__attribute__((noipa)) int
+bar (void)
+{
+  int s = 0;
+  #pragma omp parallel
+  #pragma omp for simd reduction (inscan, +:s)
+  for (int i = 0; i < 1024; i++)
+    {
+      b[i] = s;
+      #pragma omp scan exclusive(s)
+      s += 2 * a[i];
+    }
+  return s;
+}
+
+__attribute__((noipa)) void
+baz (int *a, int *b)
+{
+  #pragma omp parallel for simd simdlen (1) reduction (inscan, +:r)
+  for (int i = 0; i < 1024; i++)
+    {
+      b[i] = r;
+      #pragma omp scan exclusive(r)
+      r += a[i];
+    }
+}
+
+__attribute__((noipa)) int
+qux (void)
+{
+  int s = 0;
+  #pragma omp parallel for simd if (simd: 0) reduction (inscan, +:s)
+  for (int i = 0; i < 1024; i++)
+    {
+      b[i] = s;
+      #pragma omp scan exclusive(s)
+      s += 2 * a[i];
+    }
+  return s;
+}
+
+int
+main ()
+{
+  int s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      a[i] = i;
+      b[i] = -1;
+      asm ("" : "+g" (i));
+    }
+  #pragma omp parallel
+  foo (a, b);
+  if (r != 1024 * 1023 / 2)
+    abort ();
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i] != s)
+	abort ();
+      else
+	b[i] = 25;
+      s += i;
+    }
+  if (bar () != 1024 * 1023)
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i] != s)
+	abort ();
+      else
+	b[i] = -1;
+      s += 2 * i;
+    }
+  r = 0;
+  baz (a, b);
+  if (r != 1024 * 1023 / 2)
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i] != s)
+	abort ();
+      else
+	b[i] = -25;
+      s += i;
+    }
+  if (qux () != 1024 * 1023)
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i] != s)
+	abort ();
+      s += 2 * i;
+    }
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/scan-16.c.jj	2019-07-05 14:40:21.732984166 +0200
+++ libgomp/testsuite/libgomp.c/scan-16.c	2019-07-05 15:57:02.321704581 +0200
@@ -0,0 +1,120 @@ 
+/* { dg-require-effective-target size32plus } */
+/* { dg-additional-options "-O2 -fopenmp -fdump-tree-vect-details" } */
+/* { dg-additional-options "-mavx" { target avx_runtime } } */
+/* { dg-final { scan-tree-dump-times "vectorized \[2-6] loops" 2 "vect" { target sse2_runtime } } } */
+
+extern void abort (void);
+int r, a[1024], b[1024];
+
+#pragma omp declare reduction (foo: int: omp_out += omp_in) initializer (omp_priv = 0)
+
+__attribute__((noipa)) void
+foo (int *a, int *b)
+{
+  #pragma omp for simd reduction (inscan, foo:r)
+  for (int i = 0; i < 1024; i++)
+    {
+      b[i] = r;
+      #pragma omp scan exclusive(r)
+      r += a[i];
+    }
+}
+
+__attribute__((noipa)) int
+bar (void)
+{
+  int s = 0;
+  #pragma omp parallel
+  #pragma omp for simd simdlen (1) reduction (inscan, foo:s)
+  for (int i = 0; i < 1024; i++)
+    {
+      b[i] = s;
+      #pragma omp scan exclusive(s)
+      s += 2 * a[i];
+    }
+  return s;
+}
+
+__attribute__((noipa)) void
+baz (int *a, int *b)
+{
+  #pragma omp parallel for simd if (simd: 0) reduction (inscan, foo:r)
+  for (int i = 0; i < 1024; i++)
+    {
+      b[i] = r;
+      #pragma omp scan exclusive(r)
+      r += a[i];
+    }
+}
+
+__attribute__((noipa)) int
+qux (void)
+{
+  int s = 0;
+  #pragma omp parallel for simd reduction (inscan, foo:s)
+  for (int i = 0; i < 1024; i++)
+    {
+      b[i] = s;
+      #pragma omp scan exclusive(s)
+      s += 2 * a[i];
+    }
+  return s;
+}
+
+int
+main ()
+{
+  int s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      a[i] = i;
+      b[i] = -1;
+      asm ("" : "+g" (i));
+    }
+  #pragma omp parallel
+  foo (a, b);
+  if (r != 1024 * 1023 / 2)
+    abort ();
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i] != s)
+	abort ();
+      else
+	b[i] = 25;
+      s += i;
+    }
+  if (bar () != 1024 * 1023)
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i] != s)
+	abort ();
+      else
+	b[i] = -1;
+      s += 2 * i;
+    }
+  r = 0;
+  baz (a, b);
+  if (r != 1024 * 1023 / 2)
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i] != s)
+	abort ();
+      else
+	b[i] = -25;
+      s += i;
+    }
+  if (qux () != 1024 * 1023)
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i] != s)
+	abort ();
+      s += 2 * i;
+    }
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/scan-17.c.jj	2019-07-05 14:40:21.733984149 +0200
+++ libgomp/testsuite/libgomp.c/scan-17.c	2019-07-05 15:58:03.598739370 +0200
@@ -0,0 +1,89 @@ 
+/* { dg-require-effective-target size32plus } */
+/* { dg-additional-options "-O2 -fopenmp -fdump-tree-vect-details" } */
+/* { dg-additional-options "-mavx" { target avx_runtime } } */
+/* { dg-final { scan-tree-dump-times "vectorized \[2-6] loops" 2 "vect" { target sse2_runtime } } } */
+
+extern void abort (void);
+float r = 1.0f, a[1024], b[1024];
+
+__attribute__((noipa)) void
+foo (float *a, float *b)
+{
+  #pragma omp for simd reduction (inscan, *:r)
+  for (int i = 0; i < 1024; i++)
+    {
+      b[i] = r;
+      #pragma omp scan exclusive(r)
+      r *= a[i];
+    }
+}
+
+__attribute__((noipa)) float
+bar (void)
+{
+  float s = -__builtin_inff ();
+  #pragma omp parallel for simd reduction (inscan, max:s)
+  for (int i = 0; i < 1024; i++)
+    {
+      b[i] = s;
+      #pragma omp scan exclusive(s)
+      s = s > a[i] ? s : a[i];
+    }
+  return s;
+}
+
+int
+main ()
+{
+  float s = 1.0f;
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (i < 80)
+	a[i] = (i & 1) ? 0.25f : 0.5f;
+      else if (i < 200)
+	a[i] = (i % 3) == 0 ? 2.0f : (i % 3) == 1 ? 4.0f : 1.0f;
+      else if (i < 280)
+	a[i] = (i & 1) ? 0.25f : 0.5f;
+      else if (i < 380)
+	a[i] = (i % 3) == 0 ? 2.0f : (i % 3) == 1 ? 4.0f : 1.0f;
+      else
+	switch (i % 6)
+	  {
+	  case 0: a[i] = 0.25f; break;
+	  case 1: a[i] = 2.0f; break;
+	  case 2: a[i] = -1.0f; break;
+	  case 3: a[i] = -4.0f; break;
+	  case 4: a[i] = 0.5f; break;
+	  case 5: a[i] = 1.0f; break;
+	  default: a[i] = 0.0f; break;
+	  }
+      b[i] = -19.0f;
+      asm ("" : "+g" (i));
+    }
+  #pragma omp parallel
+  foo (a, b);
+  if (r * 16384.0f != 0.125f)
+    abort ();
+  float m = -175.25f;
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i] != s)
+	abort ();
+      else
+	b[i] = -231.75f;
+      s *= a[i];
+      a[i] = m - ((i % 3) == 1 ? 2.0f : (i % 3) == 2 ? 4.0f : 0.0f);
+      m += 0.75f;
+    }
+  if (bar () != 592.0f)
+    abort ();
+  s = -__builtin_inff ();
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i] != s)
+	abort ();
+      if (s < a[i])
+	s = a[i];
+    }
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/scan-18.c.jj	2019-07-05 14:40:21.735984117 +0200
+++ libgomp/testsuite/libgomp.c/scan-18.c	2019-07-05 15:58:54.311940553 +0200
@@ -0,0 +1,182 @@ 
+/* { dg-require-effective-target size32plus } */
+/* { dg-additional-options "-O2 -fopenmp -fdump-tree-vect-details" } */
+/* { dg-additional-options "-mavx" { target avx_runtime } } */
+/* { dg-final { scan-tree-dump-times "vectorized \[2-6] loops" 2 "vect" { target sse2_runtime } } } */
+
+extern void abort (void);
+int r, a[1024], b[1024];
+unsigned short r2, b2[1024];
+unsigned char r3, b3[1024];
+
+__attribute__((noipa)) void
+foo (int *a, int *b, unsigned short *b2, unsigned char *b3)
+{
+  #pragma omp for simd reduction (inscan, +:r, r2, r3)
+  for (int i = 0; i < 1024; i++)
+    {
+      {
+	b[i] = r;
+	b2[i] = r2;
+	b3[i] = r3;
+      }
+      #pragma omp scan exclusive(r, r2, r3)
+      { r += a[i]; r2 += a[i]; r3 += a[i]; }
+    }
+}
+
+__attribute__((noipa)) int
+bar (unsigned short *s2p, unsigned char *s3p)
+{
+  int s = 0;
+  unsigned short s2 = 0;
+  unsigned char s3 = 0;
+  #pragma omp parallel
+  #pragma omp for simd reduction (inscan, +:s, s2, s3)
+  for (int i = 0; i < 1024; i++)
+    {
+      { b[i] = s; b2[i] = s2; b3[i] = s3; }
+      #pragma omp scan exclusive(s, s2, s3)
+      {
+	s += 2 * a[i];
+	s2 += 2 * a[i];
+	s3 += 2 * a[i];
+      }
+    }
+  *s2p = s2;
+  *s3p = s3;
+  return s;
+}
+
+__attribute__((noipa)) void
+baz (int *a, int *b, unsigned short *b2, unsigned char *b3)
+{
+  #pragma omp parallel for simd reduction (inscan, +:r, r2, r3) if (simd: 0)
+  for (int i = 0; i < 1024; i++)
+    {
+      {
+	b[i] = r;
+	b2[i] = r2;
+	b3[i] = r3;
+      }
+      #pragma omp scan exclusive(r, r2, r3)
+      {
+	r += a[i];
+	r2 += a[i];
+	r3 += a[i];
+      }
+    }
+}
+
+__attribute__((noipa)) int
+qux (unsigned short *s2p, unsigned char *s3p)
+{
+  int s = 0;
+  unsigned short s2 = 0;
+  unsigned char s3 = 0;
+  #pragma omp parallel for simd simdlen (1) reduction (inscan, +:s, s2, s3)
+  for (int i = 0; i < 1024; i++)
+    {
+      { b[i] = s; b2[i] = s2; b3[i] = s3; }
+      #pragma omp scan exclusive(s, s2, s3)
+      { s += 2 * a[i]; s2 += 2 * a[i]; s3 += 2 * a[i]; }
+    }
+  *s2p = s2;
+  *s3p = s3;
+  return s;
+}
+
+int
+main ()
+{
+  int s = 0;
+  unsigned short s2;
+  unsigned char s3;
+  for (int i = 0; i < 1024; ++i)
+    {
+      a[i] = i;
+      b[i] = -1;
+      b2[i] = -1;
+      b3[i] = -1;
+      asm ("" : "+g" (i));
+    }
+  #pragma omp parallel
+  foo (a, b, b2, b3);
+  if (r != 1024 * 1023 / 2
+      || r2 != (unsigned short) r
+      || r3 != (unsigned char) r)
+    abort ();
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i] != s
+	  || b2[i] != (unsigned short) s
+	  || b3[i] != (unsigned char) s)
+	abort ();
+      else
+	{
+	  b[i] = 25;
+	  b2[i] = 24;
+	  b3[i] = 26;
+	}
+      s += i;
+    }
+  if (bar (&s2, &s3) != 1024 * 1023)
+    abort ();
+  if (s2 != (unsigned short) (1024 * 1023)
+      || s3 != (unsigned char) (1024 * 1023))
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i] != s
+	  || b2[i] != (unsigned short) s
+	  || b3[i] != (unsigned char) s)
+	abort ();
+      else
+	{
+	  b[i] = -1;
+	  b2[i] = -1;
+	  b3[i] = -1;
+	}
+      s += 2 * i;
+    }
+  r = 0;
+  r2 = 0;
+  r3 = 0;
+  baz (a, b, b2, b3);
+  if (r != 1024 * 1023 / 2
+      || r2 != (unsigned short) r
+      || r3 != (unsigned char) r)
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i] != s
+	  || b2[i] != (unsigned short) s
+	  || b3[i] != (unsigned char) s)
+	abort ();
+      else
+	{
+	  b[i] = 25;
+	  b2[i] = 24;
+	  b3[i] = 26;
+	}
+      s += i;
+    }
+  s2 = 0;
+  s3 = 0;
+  if (qux (&s2, &s3) != 1024 * 1023)
+    abort ();
+  if (s2 != (unsigned short) (1024 * 1023)
+      || s3 != (unsigned char) (1024 * 1023))
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i] != s
+	  || b2[i] != (unsigned short) s
+	  || b3[i] != (unsigned char) s)
+	abort ();
+      s += 2 * i;
+    }
+  return 0;
+}
--- libgomp/testsuite/libgomp.c++/scan-9.C.jj	2019-07-05 20:15:19.730797610 +0200
+++ libgomp/testsuite/libgomp.c++/scan-9.C	2019-07-05 20:16:33.312631862 +0200
@@ -0,0 +1,154 @@ 
+// { dg-require-effective-target size32plus }
+// { dg-additional-options "-O2 -fopenmp -fdump-tree-vect-details" }
+// { dg-additional-options "-mavx" { target avx_runtime } }
+// { dg-final { scan-tree-dump-times "vectorized \[2-6] loops" 2 "vect" { target sse2_runtime } } }
+
+extern "C" void abort ();
+
+struct S {
+  inline S ();
+  inline ~S ();
+  inline S (const S &);
+  inline S & operator= (const S &);
+  int s;
+};
+
+S::S () : s (0)
+{
+}
+
+S::~S ()
+{
+}
+
+S::S (const S &x)
+{
+  s = x.s;
+}
+
+S &
+S::operator= (const S &x)
+{
+  s = x.s;
+  return *this;
+}
+
+static inline void
+ini (S &x)
+{
+  x.s = 0;
+}
+
+S r, a[1024], b[1024];
+
+#pragma omp declare reduction (+: S: omp_out.s += omp_in.s)
+#pragma omp declare reduction (plus: S: omp_out.s += omp_in.s) initializer (ini (omp_priv))
+
+__attribute__((noipa)) void
+foo (S *a, S *b)
+{
+  #pragma omp for simd reduction (inscan, +:r)
+  for (int i = 0; i < 1024; i++)
+    {
+      r.s += a[i].s;
+      #pragma omp scan inclusive(r)
+      b[i] = r;
+    }
+}
+
+__attribute__((noipa)) S
+bar (void)
+{
+  S s;
+  #pragma omp parallel
+  #pragma omp for simd reduction (inscan, plus:s)
+  for (int i = 0; i < 1024; i++)
+    {
+      s.s += 2 * a[i].s;
+      #pragma omp scan inclusive(s)
+      b[i] = s;
+    }
+  return S (s);
+}
+
+__attribute__((noipa)) void
+baz (S *a, S *b)
+{
+  #pragma omp parallel for simd simdlen (1) reduction (inscan, +:r)
+  for (int i = 0; i < 1024; i++)
+    {
+      r.s += a[i].s;
+      #pragma omp scan inclusive(r)
+      b[i] = r;
+    }
+}
+
+__attribute__((noipa)) S
+qux (void)
+{
+  S s;
+  #pragma omp parallel for simd if (simd: 0) reduction (inscan, plus:s)
+  for (int i = 0; i < 1024; i++)
+    {
+      s.s += 2 * a[i].s;
+      #pragma omp scan inclusive(s)
+      b[i] = s;
+    }
+  return S (s);
+}
+
+int
+main ()
+{
+  S s;
+  for (int i = 0; i < 1024; ++i)
+    {
+      a[i].s = i;
+      b[i].s = -1;
+      asm ("" : "+g" (i));
+    }
+  #pragma omp parallel
+  foo (a, b);
+  if (r.s != 1024 * 1023 / 2)
+    abort ();
+  for (int i = 0; i < 1024; ++i)
+    {
+      s.s += i;
+      if (b[i].s != s.s)
+	abort ();
+      else
+	b[i].s = 25;
+    }
+  if (bar ().s != 1024 * 1023)
+    abort ();
+  s.s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      s.s += 2 * i;
+      if (b[i].s != s.s)
+	abort ();
+    }
+  r.s = 0;
+  baz (a, b);
+  if (r.s != 1024 * 1023 / 2)
+    abort ();
+  s.s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      s.s += i;
+      if (b[i].s != s.s)
+	abort ();
+      else
+	b[i].s = 25;
+    }
+  if (qux ().s != 1024 * 1023)
+    abort ();
+  s.s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      s.s += 2 * i;
+      if (b[i].s != s.s)
+	abort ();
+    }
+  return 0;
+}
--- libgomp/testsuite/libgomp.c++/scan-10.C.jj	2019-07-05 20:15:19.738797484 +0200
+++ libgomp/testsuite/libgomp.c++/scan-10.C	2019-07-05 20:17:21.668865758 +0200
@@ -0,0 +1,119 @@ 
+// { dg-require-effective-target size32plus }
+// { dg-additional-options "-O2 -fopenmp -fdump-tree-vect-details" }
+// { dg-additional-options "-mavx" { target avx_runtime } }
+// { dg-final { scan-tree-dump-times "vectorized \[2-6] loops" 2 "vect" { target sse2_runtime } } }
+
+extern "C" void abort ();
+int r, a[1024], b[1024], q;
+
+__attribute__((noipa)) void
+foo (int *a, int *b, int &r)
+{
+  #pragma omp for simd if (0) reduction (inscan, +:r) nowait
+  for (int i = 0; i < 1024; i++)
+    {
+      r += a[i];
+      #pragma omp scan inclusive(r)
+      b[i] = r;
+    }
+}
+
+__attribute__((noipa)) int
+bar (void)
+{
+  int &s = q;
+  q = 0;
+  #pragma omp parallel
+  #pragma omp for simd simdlen(1) reduction (inscan, +:s) nowait
+  for (int i = 0; i < 1024; i++)
+    {
+      s += 2 * a[i];
+      #pragma omp scan inclusive(s)
+      b[i] = s;
+    }
+  return s;
+}
+
+__attribute__((noipa)) void
+baz (int *a, int *b, int &r)
+{
+  #pragma omp parallel for simd reduction (inscan, +:r)
+  for (int i = 0; i < 1024; i++)
+    {
+      r += a[i];
+      #pragma omp scan inclusive(r)
+      b[i] = r;
+    }
+}
+
+__attribute__((noipa)) int
+qux (void)
+{
+  int &s = q;
+  q = 0;
+  #pragma omp parallel for simd reduction (inscan, +:s)
+  for (int i = 0; i < 1024; i++)
+    {
+      s += 2 * a[i];
+      #pragma omp scan inclusive(s)
+      b[i] = s;
+    }
+  return s;
+}
+
+int
+main ()
+{
+  int s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      a[i] = i;
+      b[i] = -1;
+      asm ("" : "+g" (i));
+    }
+  #pragma omp parallel
+  foo (a, b, r);
+  if (r != 1024 * 1023 / 2)
+    abort ();
+  for (int i = 0; i < 1024; ++i)
+    {
+      s += i;
+      if (b[i] != s)
+	abort ();
+      else
+	b[i] = 25;
+    }
+  if (bar () != 1024 * 1023)
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      s += 2 * i;
+      if (b[i] != s)
+	abort ();
+      else
+	b[i] = -1;
+    }
+  r = 0;
+  baz (a, b, r);
+  if (r != 1024 * 1023 / 2)
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      s += i;
+      if (b[i] != s)
+	abort ();
+      else
+	b[i] = -25;
+    }
+  if (qux () != 1024 * 1023)
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      s += 2 * i;
+      if (b[i] != s)
+	abort ();
+    }
+}
--- libgomp/testsuite/libgomp.c++/scan-11.C.jj	2019-07-05 20:15:19.745797373 +0200
+++ libgomp/testsuite/libgomp.c++/scan-11.C	2019-07-05 20:18:08.669121129 +0200
@@ -0,0 +1,122 @@ 
+// { dg-require-effective-target size32plus }
+// { dg-additional-options "-O2 -fopenmp -fdump-tree-vect-details" }
+// { dg-additional-options "-mavx" { target avx_runtime } }
+// { dg-final { scan-tree-dump-times "vectorized \[2-6] loops" 2 "vect" { target sse2_runtime } } }
+
+extern "C" void abort ();
+int r, a[1024], b[1024], q;
+
+#pragma omp declare reduction (foo: int: omp_out += omp_in) initializer (omp_priv = 0)
+
+__attribute__((noipa)) void
+foo (int *a, int *b, int &r)
+{
+  #pragma omp for simd reduction (inscan, foo:r)
+  for (int i = 0; i < 1024; i++)
+    {
+      r += a[i];
+      #pragma omp scan inclusive(r)
+      b[i] = r;
+    }
+}
+
+__attribute__((noipa)) int
+bar (void)
+{
+  int &s = q;
+  q = 0;
+  #pragma omp parallel
+  #pragma omp for simd reduction (inscan, foo:s) if (0)
+  for (int i = 0; i < 1024; i++)
+    {
+      s += 2 * a[i];
+      #pragma omp scan inclusive(s)
+      b[i] = s;
+    }
+  return s;
+}
+
+__attribute__((noipa)) void
+baz (int *a, int *b, int &r)
+{
+  #pragma omp parallel for simd simdlen (1) reduction (inscan, foo:r)
+  for (int i = 0; i < 1024; i++)
+    {
+      r += a[i];
+      #pragma omp scan inclusive(r)
+      b[i] = r;
+    }
+}
+
+__attribute__((noipa)) int
+qux (void)
+{
+  int &s = q;
+  q = 0;
+  #pragma omp parallel for simd reduction (inscan, foo:s)
+  for (int i = 0; i < 1024; i++)
+    {
+      s += 2 * a[i];
+      #pragma omp scan inclusive(s)
+      b[i] = s;
+    }
+  return s;
+}
+
+int
+main ()
+{
+  int s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      a[i] = i;
+      b[i] = -1;
+      asm ("" : "+g" (i));
+    }
+  #pragma omp parallel
+  foo (a, b, r);
+  if (r != 1024 * 1023 / 2)
+    abort ();
+  for (int i = 0; i < 1024; ++i)
+    {
+      s += i;
+      if (b[i] != s)
+	abort ();
+      else
+	b[i] = 25;
+    }
+  if (bar () != 1024 * 1023)
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      s += 2 * i;
+      if (b[i] != s)
+	abort ();
+      else
+	b[i] = -1;
+    }
+  r = 0;
+  baz (a, b, r);
+  if (r != 1024 * 1023 / 2)
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      s += i;
+      if (b[i] != s)
+	abort ();
+      else
+	b[i] = -25;
+    }
+  if (qux () != 1024 * 1023)
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      s += 2 * i;
+      if (b[i] != s)
+	abort ();
+    }
+  return 0;
+}
--- libgomp/testsuite/libgomp.c++/scan-12.C.jj	2019-07-05 20:15:19.752797263 +0200
+++ libgomp/testsuite/libgomp.c++/scan-12.C	2019-07-05 20:18:45.644535333 +0200
@@ -0,0 +1,153 @@ 
+// { dg-require-effective-target size32plus }
+// { dg-additional-options "-O2 -fopenmp -fdump-tree-vect-details" }
+// { dg-additional-options "-mavx" { target avx_runtime } }
+// { dg-final { scan-tree-dump-times "vectorized \[2-6] loops" 2 "vect" { target sse2_runtime } } }
+
+extern "C" void abort ();
+
+struct S {
+  inline S ();
+  inline ~S ();
+  inline S (const S &);
+  inline S & operator= (const S &);
+  int s;
+};
+
+S::S () : s (0)
+{
+}
+
+S::~S ()
+{
+}
+
+S::S (const S &x)
+{
+  s = x.s;
+}
+
+S &
+S::operator= (const S &x)
+{
+  s = x.s;
+  return *this;
+}
+
+static inline void
+ini (S &x)
+{
+  x.s = 0;
+}
+
+S r, a[1024], b[1024];
+
+#pragma omp declare reduction (+: S: omp_out.s += omp_in.s)
+#pragma omp declare reduction (plus: S: omp_out.s += omp_in.s) initializer (ini (omp_priv))
+
+__attribute__((noipa)) void
+foo (S *a, S *b, S &r)
+{
+  #pragma omp for simd reduction (inscan, +:r)
+  for (int i = 0; i < 1024; i++)
+    {
+      r.s += a[i].s;
+      #pragma omp scan inclusive(r)
+      b[i] = r;
+    }
+}
+
+__attribute__((noipa)) S
+bar ()
+{
+  S s;
+  #pragma omp parallel
+  #pragma omp for simd reduction (inscan, plus:s)
+  for (int i = 0; i < 1024; i++)
+    {
+      s.s += 2 * a[i].s;
+      #pragma omp scan inclusive(s)
+      b[i] = s;
+    }
+  return s;
+}
+
+__attribute__((noipa)) void
+baz (S *a, S *b, S &r)
+{
+  #pragma omp parallel for simd if (simd: 0) reduction (inscan, +:r)
+  for (int i = 0; i < 1024; i++)
+    {
+      r.s += a[i].s;
+      #pragma omp scan inclusive(r)
+      b[i] = r;
+    }
+}
+
+__attribute__((noipa)) S
+qux ()
+{
+  S s;
+  #pragma omp parallel for simd reduction (inscan, plus:s) simdlen(1)
+  for (int i = 0; i < 1024; i++)
+    {
+      s.s += 2 * a[i].s;
+      #pragma omp scan inclusive(s)
+      b[i] = s;
+    }
+  return s;
+}
+
+int
+main ()
+{
+  S s;
+  for (int i = 0; i < 1024; ++i)
+    {
+      a[i].s = i;
+      b[i].s = -1;
+      asm ("" : "+g" (i));
+    }
+  #pragma omp parallel
+  foo (a, b, r);
+  if (r.s != 1024 * 1023 / 2)
+    abort ();
+  for (int i = 0; i < 1024; ++i)
+    {
+      s.s += i;
+      if (b[i].s != s.s)
+	abort ();
+      else
+	b[i].s = 25;
+    }
+  if (bar ().s != 1024 * 1023)
+    abort ();
+  s.s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      s.s += 2 * i;
+      if (b[i].s != s.s)
+	abort ();
+    }
+  r.s = 0;
+  baz (a, b, r);
+  if (r.s != 1024 * 1023 / 2)
+    abort ();
+  s.s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      s.s += i;
+      if (b[i].s != s.s)
+	abort ();
+      else
+	b[i].s = 25;
+    }
+  if (qux ().s != 1024 * 1023)
+    abort ();
+  s.s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      s.s += 2 * i;
+      if (b[i].s != s.s)
+	abort ();
+    }
+}
--- libgomp/testsuite/libgomp.c++/scan-13.C.jj	2019-07-05 20:15:19.758797168 +0200
+++ libgomp/testsuite/libgomp.c++/scan-13.C	2019-07-05 21:25:28.540885582 +0200
@@ -0,0 +1,161 @@ 
+// { dg-require-effective-target size32plus }
+// { dg-additional-options "-O2 -fopenmp -fdump-tree-vect-details" }
+// { dg-additional-options "-mavx" { target avx_runtime } }
+// { dg-final { scan-tree-dump-times "vectorized \[2-6] loops" 2 "vect" { xfail *-*-* } } }
+
+extern "C" void abort ();
+
+template <typename T>
+struct S {
+  inline S ();
+  inline ~S ();
+  inline S (const S &);
+  inline S & operator= (const S &);
+  T s;
+};
+
+template <typename T>
+S<T>::S () : s (0)
+{
+}
+
+template <typename T>
+S<T>::~S ()
+{
+}
+
+template <typename T>
+S<T>::S (const S &x)
+{
+  s = x.s;
+}
+
+template <typename T>
+S<T> &
+S<T>::operator= (const S &x)
+{
+  s = x.s;
+  return *this;
+}
+
+template <typename T>
+static inline void
+ini (S<T> &x)
+{
+  x.s = 0;
+}
+
+S<int> r, a[1024], b[1024];
+
+#pragma omp declare reduction (+: S<int>: omp_out.s += omp_in.s)
+#pragma omp declare reduction (plus: S<int>: omp_out.s += omp_in.s) initializer (ini (omp_priv))
+
+template <typename T>
+__attribute__((noipa)) void
+foo (S<T> *a, S<T> *b)
+{
+  #pragma omp for simd if (0) reduction (inscan, +:r)
+  for (int i = 0; i < 1024; i++)
+    {
+      b[i] = r;
+      #pragma omp scan exclusive(r)
+      r.s += a[i].s;
+    }
+}
+
+template <typename T>
+__attribute__((noipa)) S<T>
+bar (void)
+{
+  S<T> s;
+  #pragma omp parallel
+  #pragma omp for simd reduction (inscan, plus:s)
+  for (int i = 0; i < 1024; i++)
+    {
+      b[i] = s;
+      #pragma omp scan exclusive(s)
+      s.s += 2 * a[i].s;
+    }
+  return S<T> (s);
+}
+
+__attribute__((noipa)) void
+baz (S<int> *a, S<int> *b)
+{
+  #pragma omp parallel for simd reduction (inscan, +:r)
+  for (int i = 0; i < 1024; i++)
+    {
+      b[i] = r;
+      #pragma omp scan exclusive(r)
+      r.s += a[i].s;
+    }
+}
+
+__attribute__((noipa)) S<int>
+qux (void)
+{
+  S<int> s;
+  #pragma omp parallel for simd simdlen(1) reduction (inscan, plus:s)
+  for (int i = 0; i < 1024; i++)
+    {
+      b[i] = s;
+      #pragma omp scan exclusive(s)
+      s.s += 2 * a[i].s;
+    }
+  return S<int> (s);
+}
+
+int
+main ()
+{
+  S<int> s;
+  for (int i = 0; i < 1024; ++i)
+    {
+      a[i].s = i;
+      b[i].s = -1;
+      asm ("" : "+g" (i));
+    }
+  #pragma omp parallel
+  foo (a, b);
+  if (r.s != 1024 * 1023 / 2)
+    abort ();
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i].s != s.s)
+	abort ();
+      else
+	b[i].s = 25;
+      s.s += i;
+    }
+  if (bar<int> ().s != 1024 * 1023)
+    abort ();
+  s.s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i].s != s.s)
+	abort ();
+      s.s += 2 * i;
+    }
+  r.s = 0;
+  baz (a, b);
+  if (r.s != 1024 * 1023 / 2)
+    abort ();
+  s.s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i].s != s.s)
+	abort ();
+      else
+	b[i].s = 25;
+      s.s += i;
+    }
+  if (qux ().s != 1024 * 1023)
+    abort ();
+  s.s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i].s != s.s)
+	abort ();
+      s.s += 2 * i;
+    }
+}
--- libgomp/testsuite/libgomp.c++/scan-14.C.jj	2019-07-05 20:15:19.765797057 +0200
+++ libgomp/testsuite/libgomp.c++/scan-14.C	2019-07-05 20:20:10.433192030 +0200
@@ -0,0 +1,123 @@ 
+// { dg-require-effective-target size32plus }
+// { dg-additional-options "-O2 -fopenmp -fdump-tree-vect-details" }
+// { dg-additional-options "-mavx" { target avx_runtime } }
+// { dg-final { scan-tree-dump-times "vectorized \[2-6] loops" 2 "vect" { target sse2_runtime } } }
+
+extern "C" void abort ();
+int r, a[1024], b[1024], q;
+
+template <typename T, typename U>
+__attribute__((noipa)) void
+foo (T a, T b, U r)
+{
+  #pragma omp for simd if (0) reduction (inscan, +:r)
+  for (int i = 0; i < 1024; i++)
+    {
+      b[i] = r;
+      #pragma omp scan exclusive(r)
+      r += a[i];
+    }
+}
+
+template <typename T>
+__attribute__((noipa)) T
+bar ()
+{
+  T &s = q;
+  q = 0;
+  #pragma omp parallel
+  #pragma omp for simd reduction (inscan, +:s) simdlen(1)
+  for (int i = 0; i < 1024; i++)
+    {
+      b[i] = s;
+      #pragma omp scan exclusive(s)
+      s += 2 * a[i];
+    }
+  return s;
+}
+
+template <typename T>
+__attribute__((noipa)) void
+baz (T *a, T *b, T &r)
+{
+  #pragma omp parallel for simd reduction (inscan, +:r)
+  for (T i = 0; i < 1024; i++)
+    {
+      b[i] = r;
+      #pragma omp scan exclusive(r)
+      r += a[i];
+    }
+}
+
+template <typename T>
+__attribute__((noipa)) int
+qux ()
+{
+  T s = q;
+  q = 0;
+  #pragma omp parallel for simd reduction (inscan, +:s)
+  for (int i = 0; i < 1024; i++)
+    {
+      b[i] = s;
+      #pragma omp scan exclusive(s)
+      s += 2 * a[i];
+    }
+  return s;
+}
+
+int
+main ()
+{
+  int s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      a[i] = i;
+      b[i] = -1;
+      asm ("" : "+g" (i));
+    }
+  #pragma omp parallel
+  foo<int *, int &> (a, b, r);
+  if (r != 1024 * 1023 / 2)
+    abort ();
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i] != s)
+	abort ();
+      else
+	b[i] = 25;
+      s += i;
+    }
+  if (bar<int> () != 1024 * 1023)
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i] != s)
+	abort ();
+      else
+	b[i] = -1;
+      s += 2 * i;
+    }
+  r = 0;
+  baz<int> (a, b, r);
+  if (r != 1024 * 1023 / 2)
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i] != s)
+	abort ();
+      else
+	b[i] = -25;
+      s += i;
+    }
+  if (qux<int &> () != 1024 * 1023)
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i] != s)
+	abort ();
+      s += 2 * i;
+    }
+}
--- libgomp/testsuite/libgomp.c++/scan-15.C.jj	2019-07-05 20:15:19.771796963 +0200
+++ libgomp/testsuite/libgomp.c++/scan-15.C	2019-07-05 20:20:42.912677458 +0200
@@ -0,0 +1,121 @@ 
+// { dg-require-effective-target size32plus }
+// { dg-additional-options "-O2 -fopenmp -fdump-tree-vect-details" }
+// { dg-additional-options "-mavx" { target avx_runtime } }
+// { dg-final { scan-tree-dump-times "vectorized \[2-6] loops" 2 "vect" { target sse2_runtime } } }
+
+extern "C" void abort ();
+int r, a[1024], b[1024], q;
+
+#pragma omp declare reduction (foo: int: omp_out += omp_in) initializer (omp_priv = 0)
+
+__attribute__((noipa)) void
+foo (int *a, int *b, int &r)
+{
+  #pragma omp for simd reduction (inscan, foo:r)
+  for (int i = 0; i < 1024; i++)
+    {
+      b[i] = r;
+      #pragma omp scan exclusive(r)
+      r += a[i];
+    }
+}
+
+__attribute__((noipa)) int
+bar (void)
+{
+  int &s = q;
+  q = 0;
+  #pragma omp parallel
+  #pragma omp for simd reduction (inscan, foo:s) nowait
+  for (int i = 0; i < 1024; i++)
+    {
+      b[i] = s;
+      #pragma omp scan exclusive(s)
+      s += 2 * a[i];
+    }
+  return s;
+}
+
+__attribute__((noipa)) void
+baz (int *a, int *b, int &r)
+{
+  #pragma omp parallel for simd reduction (inscan, foo:r) if (simd: 0)
+  for (int i = 0; i < 1024; i++)
+    {
+      b[i] = r;
+      #pragma omp scan exclusive(r)
+      r += a[i];
+    }
+}
+
+__attribute__((noipa)) int
+qux (void)
+{
+  int &s = q;
+  q = 0;
+  #pragma omp parallel for simd reduction (inscan, foo:s)simdlen(1)
+  for (int i = 0; i < 1024; i++)
+    {
+      b[i] = s;
+      #pragma omp scan exclusive(s)
+      s += 2 * a[i];
+    }
+  return s;
+}
+
+int
+main ()
+{
+  int s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      a[i] = i;
+      b[i] = -1;
+      asm ("" : "+g" (i));
+    }
+  #pragma omp parallel
+  foo (a, b, r);
+  if (r != 1024 * 1023 / 2)
+    abort ();
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i] != s)
+	abort ();
+      else
+	b[i] = 25;
+      s += i;
+    }
+  if (bar () != 1024 * 1023)
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i] != s)
+	abort ();
+      else
+	b[i] = -1;
+      s += 2 * i;
+    }
+  r = 0;
+  baz (a, b, r);
+  if (r != 1024 * 1023 / 2)
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i] != s)
+	abort ();
+      else
+	b[i] = -25;
+      s += i;
+    }
+  if (qux () != 1024 * 1023)
+    abort ();
+  s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i] != s)
+	abort ();
+      s += 2 * i;
+    }
+}
--- libgomp/testsuite/libgomp.c++/scan-16.C.jj	2019-07-05 20:15:19.778796852 +0200
+++ libgomp/testsuite/libgomp.c++/scan-16.C	2019-07-05 21:25:39.623708697 +0200
@@ -0,0 +1,153 @@ 
+// { dg-require-effective-target size32plus }
+// { dg-additional-options "-O2 -fopenmp -fdump-tree-vect-details" }
+// { dg-additional-options "-mavx" { target avx_runtime } }
+// { dg-final { scan-tree-dump-times "vectorized \[2-6] loops" 2 "vect" { xfail *-*-* } } }
+
+extern "C" void abort ();
+
+struct S {
+  inline S ();
+  inline ~S ();
+  inline S (const S &);
+  inline S & operator= (const S &);
+  int s;
+};
+
+S::S () : s (0)
+{
+}
+
+S::~S ()
+{
+}
+
+S::S (const S &x)
+{
+  s = x.s;
+}
+
+S &
+S::operator= (const S &x)
+{
+  s = x.s;
+  return *this;
+}
+
+static inline void
+ini (S &x)
+{
+  x.s = 0;
+}
+
+S r, a[1024], b[1024];
+
+#pragma omp declare reduction (+: S: omp_out.s += omp_in.s)
+#pragma omp declare reduction (plus: S: omp_out.s += omp_in.s) initializer (ini (omp_priv))
+
+__attribute__((noipa)) void
+foo (S *a, S *b, S &r)
+{
+  #pragma omp for simd simdlen (1) reduction (inscan, +:r)
+  for (int i = 0; i < 1024; i++)
+    {
+      b[i] = r;
+      #pragma omp scan exclusive(r)
+      r.s += a[i].s;
+    }
+}
+
+__attribute__((noipa)) S
+bar (void)
+{
+  S s;
+  #pragma omp parallel
+  #pragma omp for simd if (0) reduction (inscan, plus:s)
+  for (int i = 0; i < 1024; i++)
+    {
+      b[i] = s;
+      #pragma omp scan exclusive(s)
+      s.s += 2 * a[i].s;
+    }
+  return s;
+}
+
+__attribute__((noipa)) void
+baz (S *a, S *b, S &r)
+{
+  #pragma omp parallel for simd reduction (inscan, +:r)
+  for (int i = 0; i < 1024; i++)
+    {
+      b[i] = r;
+      #pragma omp scan exclusive(r)
+      r.s += a[i].s;
+    }
+}
+
+__attribute__((noipa)) S
+qux (void)
+{
+  S s;
+  #pragma omp parallel for simd reduction (inscan, plus:s)
+  for (int i = 0; i < 1024; i++)
+    {
+      b[i] = s;
+      #pragma omp scan exclusive(s)
+      s.s += 2 * a[i].s;
+    }
+  return s;
+}
+
+int
+main ()
+{
+  S s;
+  for (int i = 0; i < 1024; ++i)
+    {
+      a[i].s = i;
+      b[i].s = -1;
+      asm ("" : "+g" (i));
+    }
+  #pragma omp parallel
+  foo (a, b, r);
+  if (r.s != 1024 * 1023 / 2)
+    abort ();
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i].s != s.s)
+	abort ();
+      else
+	b[i].s = 25;
+      s.s += i;
+    }
+  if (bar ().s != 1024 * 1023)
+    abort ();
+  s.s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i].s != s.s)
+	abort ();
+      s.s += 2 * i;
+    }
+  r.s = 0;
+  baz (a, b, r);
+  if (r.s != 1024 * 1023 / 2)
+    abort ();
+  s.s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i].s != s.s)
+	abort ();
+      else
+	b[i].s = 25;
+      s.s += i;
+    }
+  if (qux ().s != 1024 * 1023)
+    abort ();
+  s.s = 0;
+  for (int i = 0; i < 1024; ++i)
+    {
+      if (b[i].s != s.s)
+	abort ();
+      s.s += 2 * i;
+    }
+}