public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/omp/gcc-11] openmp: in_reduction clause support on target construct
@ 2021-08-25 15:06 Chung-Lin Tang
  0 siblings, 0 replies; only message in thread
From: Chung-Lin Tang @ 2021-08-25 15:06 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:aa75f5e93ac694f53ad354396c552c21034c9f94

commit aa75f5e93ac694f53ad354396c552c21034c9f94
Author: Chung-Lin Tang <cltang@codesourcery.com>
Date:   Wed Aug 25 23:03:20 2021 +0800

    openmp: in_reduction clause support on target construct
    
    (backport of commit 7619d33471c10fe3d149dcbb701d99ed3dd23528 from mainline)
    
    This patch adds support for in_reduction clause on target construct, though
    for now only for synchronous targets (without nowait clause).
    The encountering thread in that case runs the target task and blocks until
    the target region ends, so it is implemented by remapping it before entering
    the target, initializing the private copy if not yet initialized for the
    current thread and then using the remapped addresses for the mapping
    addresses.
    For nowait combined with in_reduction the patch contains a hack where the
    nowait clause is ignored.  To implement it correctly, I think we would need
    to create a new private variable for the in_reduction and initialize it before
    doing the async target and adjust the map addresses to that private variable
    and then pass a function pointer to the library routine with code where the callback
    would remap the address to the current threads private variable and use in_reduction
    combiner to combine the private variable we've created into the thread's copy.
    The library would then need to make sure that the routine is called in some thread
    participating in the parallel (and not in an unshackeled thread).
    
    2021-06-24  Jakub Jelinek  <jakub@redhat.com>
    
    gcc/
            * tree.h (OMP_CLAUSE_MAP_IN_REDUCTION): Document meaning for OpenMP.
            * gimplify.c (gimplify_scan_omp_clauses): For OpenMP map clauses
            with OMP_CLAUSE_MAP_IN_REDUCTION flag partially defer gimplification
            of non-decl OMP_CLAUSE_DECL.  For OMP_CLAUSE_IN_REDUCTION on
            OMP_TARGET user outer_ctx instead of ctx for placeholders and
            initializer/combiner gimplification.
            * omp-low.c (scan_sharing_clauses): Handle OMP_CLAUSE_MAP_IN_REDUCTION
            on target constructs.
            (lower_rec_input_clauses): Likewise.
            (lower_omp_target): Likewise.
            * omp-expand.c (expand_omp_target): Temporarily ignore nowait clause
            on target if in_reduction is present.
    gcc/c-family/
            * c-common.h (enum c_omp_region_type): Add C_ORT_TARGET and
            C_ORT_OMP_TARGET.
            * c-omp.c (c_omp_split_clauses): For OMP_CLAUSE_IN_REDUCTION on
            combined target constructs also add map (always, tofrom:) clause.
    gcc/c/
            * c-parser.c (omp_split_clauses): Pass C_ORT_OMP_TARGET instead of
            C_ORT_OMP for clauses on target construct.
            (OMP_TARGET_CLAUSE_MASK): Add in_reduction clause.
            (c_parser_omp_target): For non-combined target add
            map (always, tofrom:) clauses for OMP_CLAUSE_IN_REDUCTION.  Pass
            C_ORT_OMP_TARGET to c_finish_omp_clauses.
            * c-typeck.c (handle_omp_array_sections): Adjust ort handling
            for addition of C_ORT_OMP_TARGET and simplify, mapping clauses are
            never present on C_ORT_*DECLARE_SIMD.
            (c_finish_omp_clauses): Likewise.  Handle OMP_CLAUSE_IN_REDUCTION
            on C_ORT_OMP_TARGET, set OMP_CLAUSE_MAP_IN_REDUCTION on
            corresponding map clauses.
    gcc/cp/
            * parser.c (cp_omp_split_clauses): Pass C_ORT_OMP_TARGET instead of
            C_ORT_OMP for clauses on target construct.
            (OMP_TARGET_CLAUSE_MASK): Add in_reduction clause.
            (cp_parser_omp_target): For non-combined target add
            map (always, tofrom:) clauses for OMP_CLAUSE_IN_REDUCTION.  Pass
            C_ORT_OMP_TARGET to finish_omp_clauses.
            * semantics.c (handle_omp_array_sections_1): Adjust ort handling
            for addition of C_ORT_OMP_TARGET and simplify, mapping clauses are
            never present on C_ORT_*DECLARE_SIMD.
            (handle_omp_array_sections): Likewise.
            (finish_omp_clauses): Likewise.  Handle OMP_CLAUSE_IN_REDUCTION
            on C_ORT_OMP_TARGET, set OMP_CLAUSE_MAP_IN_REDUCTION on
            corresponding map clauses.
            * pt.c (tsubst_expr): Pass C_ORT_OMP_TARGET instead of C_ORT_OMP for
            clauses on target construct.
    gcc/testsuite/
            * c-c++-common/gomp/target-in-reduction-1.c: New test.
            * c-c++-common/gomp/clauses-1.c: Add in_reduction clauses on
            target or combined target constructs.
    libgomp/
            * testsuite/libgomp.c-c++-common/target-in-reduction-1.c: New test.
            * testsuite/libgomp.c-c++-common/target-in-reduction-2.c: New test.
            * testsuite/libgomp.c++/target-in-reduction-1.C: New test.
            * testsuite/libgomp.c++/target-in-reduction-2.C: New test.

Diff:
---
 gcc/c-family/c-common.h                            |   4 +-
 gcc/c-family/c-omp.c                               |  13 ++
 gcc/c/c-parser.c                                   |  18 +-
 gcc/c/c-typeck.c                                   | 131 +++++++------
 gcc/cp/parser.c                                    |  19 +-
 gcc/cp/pt.c                                        |   9 +-
 gcc/cp/semantics.c                                 | 146 ++++++++-------
 gcc/gimplify.c                                     | 126 ++++++++++++-
 gcc/omp-expand.c                                   |   4 +
 gcc/omp-low.c                                      | 203 +++++++++++++++++++--
 gcc/testsuite/c-c++-common/gomp/clauses-1.c        |  30 +--
 .../c-c++-common/gomp/target-in-reduction-1.c      |  12 ++
 gcc/tree-pretty-print.c                            |   9 +-
 gcc/tree.h                                         |   3 +-
 .../testsuite/libgomp.c++/target-in-reduction-1.C  | 113 ++++++++++++
 .../testsuite/libgomp.c++/target-in-reduction-2.C  | 182 ++++++++++++++++++
 .../libgomp.c-c++-common/target-in-reduction-1.c   | 104 +++++++++++
 .../libgomp.c-c++-common/target-in-reduction-2.c   | 173 ++++++++++++++++++
 18 files changed, 1134 insertions(+), 165 deletions(-)

diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 0043fc47ea2..bab339bce87 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1207,7 +1207,9 @@ enum c_omp_region_type
   C_ORT_OMP			= 1 << 0,
   C_ORT_ACC			= 1 << 1,
   C_ORT_DECLARE_SIMD		= 1 << 2,
-  C_ORT_OMP_DECLARE_SIMD	= C_ORT_OMP | C_ORT_DECLARE_SIMD
+  C_ORT_TARGET			= 1 << 3,
+  C_ORT_OMP_DECLARE_SIMD	= C_ORT_OMP | C_ORT_DECLARE_SIMD,
+  C_ORT_OMP_TARGET		= C_ORT_OMP | C_ORT_TARGET
 };
 
 extern tree c_finish_omp_master (location_t, tree);
diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c
index c8634701742..cecc1f96b4d 100644
--- a/gcc/c-family/c-omp.c
+++ b/gcc/c-family/c-omp.c
@@ -2261,6 +2261,19 @@ c_omp_split_clauses (location_t loc, enum tree_code code,
 	    s = C_OMP_CLAUSE_SPLIT_TEAMS;
 	  break;
 	case OMP_CLAUSE_IN_REDUCTION:
+	  if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)) != 0)
+	    {
+	      /* When on target, map(always, tofrom: item) is added as
+		 well.  For non-combined target it is added in the FEs.  */
+	      c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses),
+				    OMP_CLAUSE_MAP);
+	      OMP_CLAUSE_DECL (c) = OMP_CLAUSE_DECL (clauses);
+	      OMP_CLAUSE_SET_MAP_KIND (c, GOMP_MAP_ALWAYS_TOFROM);
+	      OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET];
+	      cclauses[C_OMP_CLAUSE_SPLIT_TARGET] = c;
+	      s = C_OMP_CLAUSE_SPLIT_TARGET;
+	      break;
+	    }
 	  /* in_reduction on taskloop simd becomes reduction on the simd
 	     and keeps being in_reduction on taskloop.  */
 	  if (code == OMP_SIMD)
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 9920eb1d5d0..166a171048d 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -18824,7 +18824,9 @@ omp_split_clauses (location_t loc, enum tree_code code,
   c_omp_split_clauses (loc, code, mask, clauses, cclauses);
   for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++)
     if (cclauses[i])
-      cclauses[i] = c_finish_omp_clauses (cclauses[i], C_ORT_OMP);
+      cclauses[i] = c_finish_omp_clauses (cclauses[i],
+					  i == C_OMP_CLAUSE_SPLIT_TARGET
+					  ? C_ORT_OMP_TARGET : C_ORT_OMP);
 }
 
 /* OpenMP 5.0:
@@ -20269,6 +20271,7 @@ c_parser_omp_target_exit_data (location_t loc, c_parser *parser,
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULTMAP)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR))
 
 static bool
@@ -20433,7 +20436,18 @@ c_parser_omp_target (c_parser *parser, enum pragma_context context, bool *if_p)
 
   OMP_TARGET_CLAUSES (stmt)
     = c_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK,
-				"#pragma omp target");
+				"#pragma omp target", false);
+  for (tree c = OMP_TARGET_CLAUSES (stmt); c; c = OMP_CLAUSE_CHAIN (c))
+    if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION)
+      {
+	tree nc = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP);
+	OMP_CLAUSE_DECL (nc) = OMP_CLAUSE_DECL (c);
+	OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_ALWAYS_TOFROM);
+	OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (c);
+	OMP_CLAUSE_CHAIN (c) = nc;
+      }
+  OMP_TARGET_CLAUSES (stmt)
+    = c_finish_omp_clauses (OMP_TARGET_CLAUSES (stmt), C_ORT_OMP_TARGET);
   c_omp_adjust_map_clauses (OMP_TARGET_CLAUSES (stmt), true);
 
   pc = &OMP_TARGET_CLAUSES (stmt);
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index a8b54c676c0..814ca7720a1 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -13128,16 +13128,15 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
 		  return error_mark_node;
 		}
 	      t = TREE_OPERAND (t, 0);
-	      if (ort == C_ORT_ACC || ort == C_ORT_OMP)
-		while (TREE_CODE (t) == MEM_REF
-		       || TREE_CODE (t) == INDIRECT_REF
-		       || TREE_CODE (t) == ARRAY_REF)
-		  {
+	      while (TREE_CODE (t) == MEM_REF
+		     || TREE_CODE (t) == INDIRECT_REF
+		     || TREE_CODE (t) == ARRAY_REF)
+		{
+		  t = TREE_OPERAND (t, 0);
+		  STRIP_NOPS (t);
+		  if (TREE_CODE (t) == POINTER_PLUS_EXPR)
 		    t = TREE_OPERAND (t, 0);
-		    STRIP_NOPS (t);
-		    if (TREE_CODE (t) == POINTER_PLUS_EXPR)
-		      t = TREE_OPERAND (t, 0);
-		  }
+		}
 	      if (ort == C_ORT_ACC && TREE_CODE (t) == MEM_REF)
 		{
 		  if (maybe_ne (mem_ref_offset (t), 0))
@@ -13439,7 +13438,7 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
 	      tree d_length = TREE_VALUE (d);
 	      if (d_length == NULL_TREE || !integer_onep (d_length))
 		{
-		  if (ort == C_ORT_ACC)
+		  if (ort == C_ORT_ACC && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP)
 		    {
 		      while (TREE_CODE (d) == TREE_LIST)
 			d = TREE_CHAIN (d);
@@ -13719,32 +13718,29 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort)
 	      && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE))
 	return false;
       gcc_assert (OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_FORCE_DEVICEPTR);
-      if (ort == C_ORT_OMP || ort == C_ORT_ACC)
-	switch (OMP_CLAUSE_MAP_KIND (c))
-	  {
-	  case GOMP_MAP_ALLOC:
-	  case GOMP_MAP_IF_PRESENT:
-	  case GOMP_MAP_TO:
-	  case GOMP_MAP_FROM:
-	  case GOMP_MAP_TOFROM:
-	  case GOMP_MAP_ALWAYS_TO:
-	  case GOMP_MAP_ALWAYS_FROM:
-	  case GOMP_MAP_ALWAYS_TOFROM:
-	  case GOMP_MAP_RELEASE:
-	  case GOMP_MAP_DELETE:
-	  case GOMP_MAP_FORCE_TO:
-	  case GOMP_MAP_FORCE_FROM:
-	  case GOMP_MAP_FORCE_TOFROM:
-	  case GOMP_MAP_FORCE_PRESENT:
-	    OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION (c) = 1;
-	    break;
-	  default:
-	    break;
-	  }
+      switch (OMP_CLAUSE_MAP_KIND (c))
+	{
+	case GOMP_MAP_ALLOC:
+	case GOMP_MAP_IF_PRESENT:
+	case GOMP_MAP_TO:
+	case GOMP_MAP_FROM:
+	case GOMP_MAP_TOFROM:
+	case GOMP_MAP_ALWAYS_TO:
+	case GOMP_MAP_ALWAYS_FROM:
+	case GOMP_MAP_ALWAYS_TOFROM:
+	case GOMP_MAP_RELEASE:
+	case GOMP_MAP_DELETE:
+	case GOMP_MAP_FORCE_TO:
+	case GOMP_MAP_FORCE_FROM:
+	case GOMP_MAP_FORCE_TOFROM:
+	case GOMP_MAP_FORCE_PRESENT:
+	  OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION (c) = 1;
+	  break;
+	default:
+	  break;
+	}
       tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP);
-      if (ort != C_ORT_OMP && ort != C_ORT_ACC)
-	OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_POINTER);
-      else if (TREE_CODE (t) == COMPONENT_REF)
+      if (TREE_CODE (t) == COMPONENT_REF)
 	OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ATTACH_DETACH);
       else
 	OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_FIRSTPRIVATE_POINTER);
@@ -14043,6 +14039,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
   bool allocate_seen = false;
   bool implicit_moved = false;
   bool oacc_gang_seen = false;
+  bool target_in_reduction_seen = false;
 
   bitmap_obstack_initialize (NULL);
   bitmap_initialize (&generic_head, &bitmap_default_obstack);
@@ -14054,7 +14051,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
   bitmap_initialize (&map_field_head, &bitmap_default_obstack);
   bitmap_initialize (&map_firstprivate_head, &bitmap_default_obstack);
   /* If ort == C_ORT_OMP used as nontemporal_head or use_device_xxx_head
-     instead.  */
+     instead and for ort == C_ORT_OMP_TARGET used as in_reduction_head.  */
   bitmap_initialize (&oacc_reduction_head, &bitmap_default_obstack);
 
   if (ort & C_ORT_ACC)
@@ -14462,8 +14459,22 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 		   || (ort == C_ORT_OMP
 		       && (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_USE_DEVICE_PTR
 			   || (OMP_CLAUSE_CODE (c)
-			       == OMP_CLAUSE_USE_DEVICE_ADDR))))
+			       == OMP_CLAUSE_USE_DEVICE_ADDR)))
+		   || (ort == C_ORT_OMP_TARGET
+		       && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION))
 	    {
+	      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION
+		  && (bitmap_bit_p (&generic_head, DECL_UID (t))
+		      || bitmap_bit_p (&firstprivate_head, DECL_UID (t))))
+		{
+		  error_at (OMP_CLAUSE_LOCATION (c),
+			    "%qD appears more than once in data-sharing "
+			    "clauses", t);
+		  remove = true;
+		  break;
+		}
+	      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION)
+		target_in_reduction_seen = true;
 	      if (bitmap_bit_p (&oacc_reduction_head, DECL_UID (t)))
 		{
 		  error_at (OMP_CLAUSE_LOCATION (c),
@@ -14478,7 +14489,8 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 	    }
 	  else if (bitmap_bit_p (&generic_head, DECL_UID (t))
 		   || bitmap_bit_p (&firstprivate_head, DECL_UID (t))
-		   || bitmap_bit_p (&lastprivate_head, DECL_UID (t)))
+		   || bitmap_bit_p (&lastprivate_head, DECL_UID (t))
+		   || bitmap_bit_p (&map_firstprivate_head, DECL_UID (t)))
 	    {
 	      error_at (OMP_CLAUSE_LOCATION (c),
 			"%qE appears more than once in data clauses", t);
@@ -14545,7 +14557,8 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 		   && bitmap_bit_p (&map_firstprivate_head, DECL_UID (t)))
 	    remove = true;
 	  else if (bitmap_bit_p (&generic_head, DECL_UID (t))
-		   || bitmap_bit_p (&firstprivate_head, DECL_UID (t)))
+		   || bitmap_bit_p (&firstprivate_head, DECL_UID (t))
+		   || bitmap_bit_p (&map_firstprivate_head, DECL_UID (t)))
 	    {
 	      error_at (OMP_CLAUSE_LOCATION (c),
 			"%qE appears more than once in data clauses", t);
@@ -14926,8 +14939,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 	      STRIP_NOPS (t);
 	    }
 	  indir_component_ref_p = false;
-	  if ((ort == C_ORT_ACC || ort == C_ORT_OMP)
-	      && TREE_CODE (t) == COMPONENT_REF
+	  if (TREE_CODE (t) == COMPONENT_REF
 	      && (TREE_CODE (TREE_OPERAND (t, 0)) == MEM_REF
 		  || TREE_CODE (TREE_OPERAND (t, 0)) == INDIRECT_REF
 		  || TREE_CODE (TREE_OPERAND (t, 0)) == ARRAY_REF))
@@ -14999,7 +15011,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 	      if (VAR_P (t) || TREE_CODE (t) == PARM_DECL)
 		{
 		  if (bitmap_bit_p (&map_field_head, DECL_UID (t))
-		      || (ort == C_ORT_OMP
+		      || (ort != C_ORT_ACC
 			  && bitmap_bit_p (&map_head, DECL_UID (t))))
 		    break;
 		}
@@ -15057,7 +15069,8 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 		   && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER)
 	    {
 	      if (bitmap_bit_p (&generic_head, DECL_UID (t))
-		  || bitmap_bit_p (&firstprivate_head, DECL_UID (t)))
+		  || bitmap_bit_p (&firstprivate_head, DECL_UID (t))
+		  || bitmap_bit_p (&map_firstprivate_head, DECL_UID (t)))
 		{
 		  error_at (OMP_CLAUSE_LOCATION (c),
 			    "%qD appears more than once in data clauses", t);
@@ -15075,14 +15088,11 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 		  remove = true;
 		}
 	      else
-		{
-		  bitmap_set_bit (&generic_head, DECL_UID (t));
-		  bitmap_set_bit (&map_firstprivate_head, DECL_UID (t));
-		}
+		bitmap_set_bit (&map_firstprivate_head, DECL_UID (t));
 	    }
 	  else if (bitmap_bit_p (&map_head, DECL_UID (t))
 		   && !bitmap_bit_p (&map_field_head, DECL_UID (t))
-		   && ort != C_ORT_OMP)
+		   && ort == C_ORT_ACC)
 	    {
 	      if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP)
 		error_at (OMP_CLAUSE_LOCATION (c),
@@ -15095,8 +15105,8 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 			  "%qD appears more than once in map clauses", t);
 	      remove = true;
 	    }
-	  else if (bitmap_bit_p (&generic_head, DECL_UID (t))
-		   && ort == C_ORT_ACC)
+	  else if (ort == C_ORT_ACC
+		   && bitmap_bit_p (&generic_head, DECL_UID (t)))
 	    {
 	      error_at (OMP_CLAUSE_LOCATION (c),
 			"%qD appears more than once in data clauses", t);
@@ -15190,7 +15200,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 	  if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE)
 	    {
 	      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_USE_DEVICE_PTR
-		  && ort == C_ORT_OMP)
+		  && ort != C_ORT_ACC)
 		{
 		  error_at (OMP_CLAUSE_LOCATION (c),
 			    "%qs variable is not a pointer",
@@ -15477,7 +15487,10 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
       reduction_seen = -2;
     }
 
-  if (linear_variable_step_check || reduction_seen == -2 || allocate_seen)
+  if (linear_variable_step_check
+      || reduction_seen == -2
+      || allocate_seen
+      || target_in_reduction_seen)
     for (pc = &clauses, c = clauses; c ; c = *pc)
       {
 	bool remove = false;
@@ -15525,6 +15538,20 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 	else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
 		 && reduction_seen == -2)
 	  OMP_CLAUSE_REDUCTION_INSCAN (c) = 0;
+	if (target_in_reduction_seen
+	    && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP)
+	  {
+	    tree t = OMP_CLAUSE_DECL (c);
+	    while (handled_component_p (t)
+		   || TREE_CODE (t) == INDIRECT_REF
+		   || TREE_CODE (t) == ADDR_EXPR
+		   || TREE_CODE (t) == MEM_REF
+		   || TREE_CODE (t) == NON_LVALUE_EXPR)
+	      t = TREE_OPERAND (t, 0);
+	    if (DECL_P (t)
+		&& bitmap_bit_p (&oacc_reduction_head, DECL_UID (t)))
+	      OMP_CLAUSE_MAP_IN_REDUCTION (c) = 1;
+	  }
 
 	if (remove)
 	  *pc = OMP_CLAUSE_CHAIN (c);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 32fb77ae8de..86d1a446d40 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -41644,7 +41644,9 @@ cp_omp_split_clauses (location_t loc, enum tree_code code,
   c_omp_split_clauses (loc, code, mask, clauses, cclauses);
   for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++)
     if (cclauses[i])
-      cclauses[i] = finish_omp_clauses (cclauses[i], C_ORT_OMP);
+      cclauses[i] = finish_omp_clauses (cclauses[i],
+					i == C_OMP_CLAUSE_SPLIT_TARGET
+					? C_ORT_OMP_TARGET : C_ORT_OMP);
 }
 
 /* OpenMP 5.0:
@@ -43133,6 +43135,7 @@ cp_parser_omp_target_update (cp_parser *parser, cp_token *pragma_tok,
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULTMAP)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR))
 
 static bool
@@ -43281,7 +43284,19 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok,
     }
 
   tree clauses = cp_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK,
-					    "#pragma omp target", pragma_tok);
+					    "#pragma omp target", pragma_tok,
+					    false);
+  for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
+    if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION)
+      {
+	tree nc = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP);
+	OMP_CLAUSE_DECL (nc) = OMP_CLAUSE_DECL (c);
+	OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_ALWAYS_TOFROM);
+	OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (c);
+	OMP_CLAUSE_CHAIN (c) = nc;
+      }
+  clauses = finish_omp_clauses (clauses, C_ORT_OMP_TARGET);
+
   c_omp_adjust_map_clauses (clauses, true);
   keep_next_level (true);
   tree body = cp_parser_omp_structured_block (parser, if_p);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 0e87e346e45..9360d6194bd 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -18931,9 +18931,12 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
     case OACC_DATA:
     case OMP_TARGET_DATA:
     case OMP_TARGET:
-      tmp = tsubst_omp_clauses (OMP_CLAUSES (t), (TREE_CODE (t) == OACC_DATA)
-				? C_ORT_ACC : C_ORT_OMP, args, complain,
-				in_decl);
+      tmp = tsubst_omp_clauses (OMP_CLAUSES (t),
+				TREE_CODE (t) == OACC_DATA
+				? C_ORT_ACC
+				: TREE_CODE (t) == OMP_TARGET
+				? C_ORT_OMP_TARGET : C_ORT_OMP,
+				args, complain, in_decl);
       keep_next_level (true);
       stmt = begin_omp_structured_block ();
 
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index ad62ad76ff9..233acd0a77c 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -4935,8 +4935,7 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
     {
       if (error_operand_p (t))
 	return error_mark_node;
-      if ((ort == C_ORT_ACC || ort == C_ORT_OMP)
-	  && TREE_CODE (t) == FIELD_DECL)
+      if (TREE_CODE (t) == FIELD_DECL)
 	t = finish_non_static_data_member (t, NULL_TREE, NULL_TREE);
       if (REFERENCE_REF_P (t)
 	  && TREE_CODE (TREE_OPERAND (t, 0)) == COMPONENT_REF)
@@ -4978,16 +4977,15 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
 		  return error_mark_node;
 		}
 	      t = TREE_OPERAND (t, 0);
-	      if (ort == C_ORT_ACC || ort == C_ORT_OMP)
-		while (TREE_CODE (t) == MEM_REF
-		       || TREE_CODE (t) == INDIRECT_REF
-		       || TREE_CODE (t) == ARRAY_REF)
-		  {
+	      while (TREE_CODE (t) == MEM_REF
+		     || TREE_CODE (t) == INDIRECT_REF
+		     || TREE_CODE (t) == ARRAY_REF)
+		{
+		  t = TREE_OPERAND (t, 0);
+		  STRIP_NOPS (t);
+		  if (TREE_CODE (t) == POINTER_PLUS_EXPR)
 		    t = TREE_OPERAND (t, 0);
-		    STRIP_NOPS (t);
-		    if (TREE_CODE (t) == POINTER_PLUS_EXPR)
-		      t = TREE_OPERAND (t, 0);
-		  }
+		}
 	    }
 	  if (REFERENCE_REF_P (t))
 	    t = TREE_OPERAND (t, 0);
@@ -5010,7 +5008,7 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
 		      omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
 	  return error_mark_node;
 	}
-      else if (ort == C_ORT_OMP
+      else if ((ort & C_ORT_OMP_DECLARE_SIMD) == C_ORT_OMP
 	       && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP
 	       && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_TO
 	       && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_FROM
@@ -5040,7 +5038,7 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
       return ret;
     }
 
-  if (ort == C_ORT_OMP
+  if ((ort & C_ORT_OMP_DECLARE_SIMD) == C_ORT_OMP
       && (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
 	  || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION
 	  || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TASK_REDUCTION)
@@ -5305,7 +5303,7 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
 	      tree d_length = TREE_VALUE (d);
 	      if (d_length == NULL_TREE || !integer_onep (d_length))
 		{
-		  if (ort == C_ORT_ACC)
+		  if (ort == C_ORT_ACC && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP)
 		    {
 		      while (TREE_CODE (d) == TREE_LIST)
 			d = TREE_CHAIN (d);
@@ -5599,38 +5597,36 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort)
 	      || (TREE_CODE (t) == COMPONENT_REF
 		  && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE))
 	    return false;
-	  if (ort == C_ORT_OMP || ort == C_ORT_ACC)
-	    switch (OMP_CLAUSE_MAP_KIND (c))
-	      {
-	      case GOMP_MAP_ALLOC:
-	      case GOMP_MAP_IF_PRESENT:
-	      case GOMP_MAP_TO:
-	      case GOMP_MAP_FROM:
-	      case GOMP_MAP_TOFROM:
-	      case GOMP_MAP_ALWAYS_TO:
-	      case GOMP_MAP_ALWAYS_FROM:
-	      case GOMP_MAP_ALWAYS_TOFROM:
-	      case GOMP_MAP_RELEASE:
-	      case GOMP_MAP_DELETE:
-	      case GOMP_MAP_FORCE_TO:
-	      case GOMP_MAP_FORCE_FROM:
-	      case GOMP_MAP_FORCE_TOFROM:
-	      case GOMP_MAP_FORCE_PRESENT:
-		OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION (c) = 1;
-		break;
-	      default:
-		break;
-	      }
+	  switch (OMP_CLAUSE_MAP_KIND (c))
+	    {
+	    case GOMP_MAP_ALLOC:
+	    case GOMP_MAP_IF_PRESENT:
+	    case GOMP_MAP_TO:
+	    case GOMP_MAP_FROM:
+	    case GOMP_MAP_TOFROM:
+	    case GOMP_MAP_ALWAYS_TO:
+	    case GOMP_MAP_ALWAYS_FROM:
+	    case GOMP_MAP_ALWAYS_TOFROM:
+	    case GOMP_MAP_RELEASE:
+	    case GOMP_MAP_DELETE:
+	    case GOMP_MAP_FORCE_TO:
+	    case GOMP_MAP_FORCE_FROM:
+	    case GOMP_MAP_FORCE_TOFROM:
+	    case GOMP_MAP_FORCE_PRESENT:
+	      OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION (c) = 1;
+	      break;
+	    default:
+	      break;
+	    }
 	  bool reference_always_pointer = true;
 	  tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c),
 				      OMP_CLAUSE_MAP);
-	  if ((ort & C_ORT_OMP_DECLARE_SIMD) != C_ORT_OMP && ort != C_ORT_ACC)
-	    OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_POINTER);
-	  else if (TREE_CODE (t) == COMPONENT_REF)
+	  if (TREE_CODE (t) == COMPONENT_REF)
 	    {
 	      OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ATTACH_DETACH);
 
-	      if (ort == C_ORT_OMP && TYPE_REF_P (TREE_TYPE (t)))
+	      if ((ort & C_ORT_OMP_DECLARE_SIMD) == C_ORT_OMP
+		  && TYPE_REF_P (TREE_TYPE (t)))
 		{
 		  if (TREE_CODE (TREE_TYPE (TREE_TYPE (t))) == ARRAY_TYPE)
 		    OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ALWAYS_POINTER);
@@ -5644,7 +5640,8 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort)
 		   && TREE_CODE (TREE_OPERAND (t, 0)) == COMPONENT_REF)
 	    {
 	      gomp_map_kind k;
-	      if (ort == C_ORT_OMP && TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE)
+	      if ((ort & C_ORT_OMP_DECLARE_SIMD) == C_ORT_OMP
+		  && TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE)
 		k = GOMP_MAP_ATTACH_DETACH;
 	      else
 		{
@@ -6647,6 +6644,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
   bool mergeable_seen = false;
   bool implicit_moved = false;
   bool oacc_gang_seen = false;
+  bool target_in_reduction_seen = false;
 
   bitmap_obstack_initialize (NULL);
   bitmap_initialize (&generic_head, &bitmap_default_obstack);
@@ -6658,7 +6656,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
   bitmap_initialize (&map_field_head, &bitmap_default_obstack);
   bitmap_initialize (&map_firstprivate_head, &bitmap_default_obstack);
   /* If ort == C_ORT_OMP used as nontemporal_head or use_device_xxx_head
-     instead.  */
+     instead and for ort == C_ORT_OMP_TARGET used as in_reduction_head.  */
   bitmap_initialize (&oacc_reduction_head, &bitmap_default_obstack);
 
   if (ort & C_ORT_ACC)
@@ -6933,8 +6931,22 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 		   || (ort == C_ORT_OMP
 		       && (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_USE_DEVICE_PTR
 			   || (OMP_CLAUSE_CODE (c)
-			       == OMP_CLAUSE_USE_DEVICE_ADDR))))
+			       == OMP_CLAUSE_USE_DEVICE_ADDR)))
+		   || (ort == C_ORT_OMP_TARGET
+		       && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION))
 	    {
+	      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION
+		  && (bitmap_bit_p (&generic_head, DECL_UID (t))
+		      || bitmap_bit_p (&firstprivate_head, DECL_UID (t))))
+		{
+		  error_at (OMP_CLAUSE_LOCATION (c),
+			    "%qD appears more than once in data-sharing "
+			    "clauses", t);
+		  remove = true;
+		  break;
+		}
+	      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION)
+		target_in_reduction_seen = true;
 	      if (bitmap_bit_p (&oacc_reduction_head, DECL_UID (t)))
 		{
 		  error_at (OMP_CLAUSE_LOCATION (c),
@@ -6949,7 +6961,8 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 	    }
 	  else if (bitmap_bit_p (&generic_head, DECL_UID (t))
 		   || bitmap_bit_p (&firstprivate_head, DECL_UID (t))
-		   || bitmap_bit_p (&lastprivate_head, DECL_UID (t)))
+		   || bitmap_bit_p (&lastprivate_head, DECL_UID (t))
+		   || bitmap_bit_p (&map_firstprivate_head, DECL_UID (t)))
 	    {
 	      error_at (OMP_CLAUSE_LOCATION (c),
 			"%qD appears more than once in data clauses", t);
@@ -7049,7 +7062,8 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 		   && bitmap_bit_p (&map_firstprivate_head, DECL_UID (t)))
 	    remove = true;
 	  else if (bitmap_bit_p (&generic_head, DECL_UID (t))
-		   || bitmap_bit_p (&firstprivate_head, DECL_UID (t)))
+		   || bitmap_bit_p (&firstprivate_head, DECL_UID (t))
+		   || bitmap_bit_p (&map_firstprivate_head, DECL_UID (t)))
 	    {
 	      error_at (OMP_CLAUSE_LOCATION (c),
 			"%qD appears more than once in data clauses", t);
@@ -7890,8 +7904,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 	      STRIP_NOPS (t);
 	    }
 	  indir_component_ref_p = false;
-	  if ((ort == C_ORT_ACC || ort == C_ORT_OMP)
-	      && TREE_CODE (t) == COMPONENT_REF
+	  if (TREE_CODE (t) == COMPONENT_REF
 	      && (TREE_CODE (TREE_OPERAND (t, 0)) == INDIRECT_REF
 		  || TREE_CODE (TREE_OPERAND (t, 0)) == ARRAY_REF))
 	    {
@@ -7902,8 +7915,6 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 		t = TREE_OPERAND (t, 0);
 	    }
 	  if (TREE_CODE (t) == COMPONENT_REF
-	      && ((ort & C_ORT_OMP_DECLARE_SIMD) == C_ORT_OMP
-		  || ort == C_ORT_ACC)
 	      && OMP_CLAUSE_CODE (c) != OMP_CLAUSE__CACHE_)
 	    {
 	      if (type_dependent_expression_p (t))
@@ -7963,13 +7974,12 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 	      if (VAR_P (t) || TREE_CODE (t) == PARM_DECL)
 		{
 		  if (bitmap_bit_p (&map_field_head, DECL_UID (t))
-		      || (ort == C_ORT_OMP
+		      || (ort != C_ORT_ACC
 			  && bitmap_bit_p (&map_head, DECL_UID (t))))
 		    goto handle_map_references;
 		}
 	    }
-	  if ((ort == C_ORT_ACC || ort == C_ORT_OMP)
-	      && !processing_template_decl
+	  if (!processing_template_decl
 	      && TREE_CODE (t) == FIELD_DECL)
 	    {
 	      OMP_CLAUSE_DECL (c) = finish_non_static_data_member (t, NULL_TREE,
@@ -8003,7 +8013,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 	      remove = true;
 	    }
 	  else if (ort != C_ORT_ACC
-		   && ort != C_ORT_OMP
+		   && (ort & C_ORT_OMP_DECLARE_SIMD) != C_ORT_OMP
 		   && t == current_class_ptr)
 	    {
 	      error_at (OMP_CLAUSE_LOCATION (c),
@@ -8056,7 +8066,8 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 		   && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER)
 	    {
 	      if (bitmap_bit_p (&generic_head, DECL_UID (t))
-		  || bitmap_bit_p (&firstprivate_head, DECL_UID (t)))
+		  || bitmap_bit_p (&firstprivate_head, DECL_UID (t))
+		  || bitmap_bit_p (&map_firstprivate_head, DECL_UID (t)))
 		{
 		  error_at (OMP_CLAUSE_LOCATION (c),
 			    "%qD appears more than once in data clauses", t);
@@ -8074,14 +8085,11 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 		  remove = true;
 		}
 	      else
-		{
-		  bitmap_set_bit (&generic_head, DECL_UID (t));
-		  bitmap_set_bit (&map_firstprivate_head, DECL_UID (t));
-		}
+		bitmap_set_bit (&map_firstprivate_head, DECL_UID (t));
 	    }
 	  else if (bitmap_bit_p (&map_head, DECL_UID (t))
 		   && !bitmap_bit_p (&map_field_head, DECL_UID (t))
-		   && ort != C_ORT_OMP)
+		   && ort == C_ORT_ACC)
 	    {
 	      if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP)
 		error_at (OMP_CLAUSE_LOCATION (c),
@@ -8094,8 +8102,8 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 			  "%qD appears more than once in map clauses", t);
 	      remove = true;
 	    }
-	  else if (bitmap_bit_p (&generic_head, DECL_UID (t))
-		   && ort == C_ORT_ACC)
+	  else if (ort == C_ORT_ACC
+		   && bitmap_bit_p (&generic_head, DECL_UID (t)))
 	    {
 	      error_at (OMP_CLAUSE_LOCATION (c),
 			"%qD appears more than once in data clauses", t);
@@ -8674,6 +8682,22 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 	    }
 	  pc = &OMP_CLAUSE_CHAIN (c);
 	  continue;
+	case OMP_CLAUSE_MAP:
+	  if (target_in_reduction_seen && !processing_template_decl)
+	    {
+	      t = OMP_CLAUSE_DECL (c);
+	      while (handled_component_p (t)
+		     || TREE_CODE (t) == INDIRECT_REF
+		     || TREE_CODE (t) == ADDR_EXPR
+		     || TREE_CODE (t) == MEM_REF
+		     || TREE_CODE (t) == NON_LVALUE_EXPR)
+		t = TREE_OPERAND (t, 0);
+	      if (DECL_P (t)
+		  && bitmap_bit_p (&oacc_reduction_head, DECL_UID (t)))
+		OMP_CLAUSE_MAP_IN_REDUCTION (c) = 1;
+	    }
+	  pc = &OMP_CLAUSE_CHAIN (c);
+	  continue;
 	case OMP_CLAUSE_NOWAIT:
 	  if (copyprivate_seen)
 	    {
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 4e16a8f1390..d1cd91353ab 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -10289,8 +10289,116 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
 		  OMP_CLAUSE_SET_MAP_KIND (c, k);
 		}
 
-	      if (gimplify_expr (pd, pre_p, NULL, is_gimple_lvalue, fb_lvalue)
-		  == GS_ERROR)
+	      if (code == OMP_TARGET && OMP_CLAUSE_MAP_IN_REDUCTION (c))
+		{
+		  /* Don't gimplify *pd fully at this point, as the base
+		     will need to be adjusted during omp lowering.  */
+		  auto_vec<tree, 10> expr_stack;
+		  tree *p = pd;
+		  while (handled_component_p (*p)
+			 || TREE_CODE (*p) == INDIRECT_REF
+			 || TREE_CODE (*p) == ADDR_EXPR
+			 || TREE_CODE (*p) == MEM_REF
+			 || TREE_CODE (*p) == NON_LVALUE_EXPR)
+		    {
+		      expr_stack.safe_push (*p);
+		      p = &TREE_OPERAND (*p, 0);
+		    }
+		  for (int i = expr_stack.length () - 1; i >= 0; i--)
+		    {
+		      tree t = expr_stack[i];
+		      if (TREE_CODE (t) == ARRAY_REF
+			  || TREE_CODE (t) == ARRAY_RANGE_REF)
+			{
+			  if (TREE_OPERAND (t, 2) == NULL_TREE)
+			    {
+			      tree low = unshare_expr (array_ref_low_bound (t));
+			      if (!is_gimple_min_invariant (low))
+				{
+				  TREE_OPERAND (t, 2) = low;
+				  if (gimplify_expr (&TREE_OPERAND (t, 2),
+						     pre_p, NULL,
+						     is_gimple_reg,
+						     fb_rvalue) == GS_ERROR)
+				    remove = true;
+				}
+			    }
+			  else if (gimplify_expr (&TREE_OPERAND (t, 2), pre_p,
+						  NULL, is_gimple_reg,
+						  fb_rvalue) == GS_ERROR)
+			    remove = true;
+			  if (TREE_OPERAND (t, 3) == NULL_TREE)
+			    {
+			      tree elmt_size = array_ref_element_size (t);
+			      if (!is_gimple_min_invariant (elmt_size))
+				{
+				  elmt_size = unshare_expr (elmt_size);
+				  tree elmt_type
+				    = TREE_TYPE (TREE_TYPE (TREE_OPERAND (t,
+									  0)));
+				  tree factor
+				    = size_int (TYPE_ALIGN_UNIT (elmt_type));
+				  elmt_size
+				    = size_binop (EXACT_DIV_EXPR, elmt_size,
+						  factor);
+				  TREE_OPERAND (t, 3) = elmt_size;
+				  if (gimplify_expr (&TREE_OPERAND (t, 3),
+						     pre_p, NULL,
+						     is_gimple_reg,
+						     fb_rvalue) == GS_ERROR)
+				    remove = true;
+				}
+			    }
+			  else if (gimplify_expr (&TREE_OPERAND (t, 3), pre_p,
+						  NULL, is_gimple_reg,
+						  fb_rvalue) == GS_ERROR)
+			    remove = true;
+			}
+		      else if (TREE_CODE (t) == COMPONENT_REF)
+			{
+			  if (TREE_OPERAND (t, 2) == NULL_TREE)
+			    {
+			      tree offset = component_ref_field_offset (t);
+			      if (!is_gimple_min_invariant (offset))
+				{
+				  offset = unshare_expr (offset);
+				  tree field = TREE_OPERAND (t, 1);
+				  tree factor
+				    = size_int (DECL_OFFSET_ALIGN (field)
+						/ BITS_PER_UNIT);
+				  offset = size_binop (EXACT_DIV_EXPR, offset,
+						       factor);
+				  TREE_OPERAND (t, 2) = offset;
+				  if (gimplify_expr (&TREE_OPERAND (t, 2),
+						     pre_p, NULL,
+						     is_gimple_reg,
+						     fb_rvalue) == GS_ERROR)
+				    remove = true;
+				}
+			    }
+			  else if (gimplify_expr (&TREE_OPERAND (t, 2), pre_p,
+						  NULL, is_gimple_reg,
+						  fb_rvalue) == GS_ERROR)
+			    remove = true;
+			}
+		    }
+		  for (; expr_stack.length () > 0; )
+		    {
+		      tree t = expr_stack.pop ();
+
+		      if (TREE_CODE (t) == ARRAY_REF
+			  || TREE_CODE (t) == ARRAY_RANGE_REF)
+			{
+			  if (!is_gimple_min_invariant (TREE_OPERAND (t, 1))
+			      && gimplify_expr (&TREE_OPERAND (t, 1), pre_p,
+						NULL, is_gimple_val,
+						fb_rvalue) == GS_ERROR)
+			    remove = true;
+			}
+		    }
+		}
+	      else if (gimplify_expr (pd, pre_p, NULL, is_gimple_lvalue,
+				      fb_lvalue) == GS_ERROR)
 		{
 		  remove = true;
 		  break;
@@ -10507,17 +10615,21 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
 	       || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TASK_REDUCTION)
 	      && OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
 	    {
-	      omp_add_variable (ctx, OMP_CLAUSE_REDUCTION_PLACEHOLDER (c),
-				GOVD_LOCAL | GOVD_SEEN);
-	      if (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c)
+	      struct gimplify_omp_ctx *pctx
+		= code == OMP_TARGET ? outer_ctx : ctx;
+	      if (pctx)
+		omp_add_variable (pctx, OMP_CLAUSE_REDUCTION_PLACEHOLDER (c),
+				  GOVD_LOCAL | GOVD_SEEN);
+	      if (pctx
+		  && OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c)
 		  && walk_tree (&OMP_CLAUSE_REDUCTION_INIT (c),
 				find_decl_expr,
 				OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c),
 				NULL) == NULL_TREE)
-		omp_add_variable (ctx,
+		omp_add_variable (pctx,
 				  OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c),
 				  GOVD_LOCAL | GOVD_SEEN);
-	      gimplify_omp_ctxp = ctx;
+	      gimplify_omp_ctxp = pctx;
 	      push_gimplify_context ();
 
 	      OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c) = NULL;
diff --git a/gcc/omp-expand.c b/gcc/omp-expand.c
index 44f8d73fc00..c64465834cc 100644
--- a/gcc/omp-expand.c
+++ b/gcc/omp-expand.c
@@ -9666,6 +9666,10 @@ expand_omp_target (struct omp_region *region)
 	}
 
       c = omp_find_clause (clauses, OMP_CLAUSE_NOWAIT);
+      /* FIXME: in_reduction(...) nowait is unimplemented yet, pretend
+	 nowait doesn't appear.  */
+      if (c && omp_find_clause (clauses, OMP_CLAUSE_IN_REDUCTION))
+	c = NULL;
       if (c)
 	flags_i |= GOMP_TARGET_FLAG_NOWAIT;
     }
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index a6dee01d6b5..48e09acd89f 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -1383,6 +1383,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx,
 	      && ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
 		   && (OMP_CLAUSE_REDUCTION_INSCAN (c)
 		       || OMP_CLAUSE_REDUCTION_TASK (c)))
+		  || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION
 		  || is_task_ctx (ctx)))
 	    {
 	      /* For now.  */
@@ -1397,6 +1398,29 @@ scan_sharing_clauses (tree clauses, omp_context *ctx,
 	      if (TREE_CODE (t) == INDIRECT_REF
 		  || TREE_CODE (t) == ADDR_EXPR)
 		t = TREE_OPERAND (t, 0);
+	      if (is_omp_target (ctx->stmt))
+		{
+		  if (is_variable_sized (t))
+		    {
+		      gcc_assert (DECL_HAS_VALUE_EXPR_P (t));
+		      t = DECL_VALUE_EXPR (t);
+		      gcc_assert (TREE_CODE (t) == INDIRECT_REF);
+		      t = TREE_OPERAND (t, 0);
+		      gcc_assert (DECL_P (t));
+		    }
+		  tree at = t;
+		  if (ctx->outer)
+		    scan_omp_op (&at, ctx->outer);
+		  tree nt = omp_copy_decl_1 (at, ctx);
+		  splay_tree_insert (ctx->field_map,
+				     (splay_tree_key) &DECL_CONTEXT (t),
+				     (splay_tree_value) nt);
+		  if (at != t)
+		    splay_tree_insert (ctx->field_map,
+				       (splay_tree_key) &DECL_CONTEXT (at),
+				       (splay_tree_value) nt);
+		  break;
+		}
 	      install_var_local (t, ctx);
 	      if (is_taskreg_ctx (ctx)
 		  && (!is_global_var (maybe_lookup_decl_in_outer_ctx (t, ctx))
@@ -1423,6 +1447,21 @@ scan_sharing_clauses (tree clauses, omp_context *ctx,
 		}
 	      break;
 	    }
+	  if (is_omp_target (ctx->stmt))
+	    {
+	      tree at = decl;
+	      if (ctx->outer)
+		scan_omp_op (&at, ctx->outer);
+	      tree nt = omp_copy_decl_1 (at, ctx);
+	      splay_tree_insert (ctx->field_map,
+				 (splay_tree_key) &DECL_CONTEXT (decl),
+				 (splay_tree_value) nt);
+	      if (at != decl)
+		splay_tree_insert (ctx->field_map,
+				   (splay_tree_key) &DECL_CONTEXT (at),
+				   (splay_tree_value) nt);
+	      break;
+	    }
 	  if (is_task_ctx (ctx)
 	      || (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
 		  && OMP_CLAUSE_REDUCTION_TASK (c)
@@ -1733,7 +1772,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx,
 		    install_var_field (decl, true, 3, ctx, c,
 				       base_pointers_restrict);
 		  if (is_gimple_omp_offloaded (ctx->stmt)
-		      && !OMP_CLAUSE_MAP_IN_REDUCTION (c))
+		      && !(is_gimple_omp_oacc (ctx->stmt)
+			   && OMP_CLAUSE_MAP_IN_REDUCTION (c)))
 		    install_var_local (decl, ctx);
 		}
 	    }
@@ -1880,7 +1920,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx,
 	case OMP_CLAUSE_REDUCTION:
 	case OMP_CLAUSE_IN_REDUCTION:
 	  decl = OMP_CLAUSE_DECL (c);
-	  if (TREE_CODE (decl) != MEM_REF)
+	  if (TREE_CODE (decl) != MEM_REF && !is_omp_target (ctx->stmt))
 	    {
 	      if (is_variable_sized (decl))
 		install_var_local (decl, ctx);
@@ -2034,8 +2074,11 @@ scan_sharing_clauses (tree clauses, omp_context *ctx,
 	     || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TASK_REDUCTION)
 	    && OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
 	  {
-	    scan_omp (&OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c), ctx);
-	    scan_omp (&OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c), ctx);
+	    omp_context *rctx = ctx;
+	    if (is_omp_target (ctx->stmt))
+	      rctx = ctx->outer;
+	    scan_omp (&OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c), rctx);
+	    scan_omp (&OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c), rctx);
 	  }
 	else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
 		 && OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c))
@@ -5219,7 +5262,9 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
 	      break;
 	    case OMP_CLAUSE_REDUCTION:
 	    case OMP_CLAUSE_IN_REDUCTION:
-	      if (is_task_ctx (ctx) || OMP_CLAUSE_REDUCTION_TASK (c))
+	      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION
+		  || is_task_ctx (ctx)
+		  || OMP_CLAUSE_REDUCTION_TASK (c))
 		{
 		  task_reduction_p = true;
 		  if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)
@@ -5349,7 +5394,12 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
 		}
 	      new_var = var;
 	    }
-	  if (c_kind != OMP_CLAUSE_COPYIN)
+	  if (c_kind == OMP_CLAUSE_IN_REDUCTION && is_omp_target (ctx->stmt))
+	    {
+	      splay_tree_key key = (splay_tree_key) &DECL_CONTEXT (var);
+	      new_var = (tree) splay_tree_lookup (ctx->field_map, key)->value;
+	    }
+	  else if (c_kind != OMP_CLAUSE_COPYIN)
 	    new_var = lookup_decl (var, ctx);
 
 	  if (c_kind == OMP_CLAUSE_SHARED || c_kind == OMP_CLAUSE_COPYIN)
@@ -5371,7 +5421,10 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
 	      if (TREE_CODE (orig_var) == POINTER_PLUS_EXPR)
 		{
 		  tree b = TREE_OPERAND (orig_var, 1);
-		  b = maybe_lookup_decl (b, ctx);
+		  if (is_omp_target (ctx->stmt))
+		    b = NULL_TREE;
+		  else
+		    b = maybe_lookup_decl (b, ctx);
 		  if (b == NULL)
 		    {
 		      b = TREE_OPERAND (orig_var, 1);
@@ -5397,6 +5450,8 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
 			  || (TREE_CODE (TREE_TYPE (TREE_TYPE (out)))
 			      != POINTER_TYPE)))
 		    x = var;
+		  else if (is_omp_target (ctx->stmt))
+		    x = out;
 		  else
 		    {
 		      bool by_ref = use_pointer_for_field (var, NULL);
@@ -5440,7 +5495,11 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
 	      const char *name = get_name (orig_var);
 	      if (pass != 3 && !TREE_CONSTANT (v))
 		{
-		  tree t = maybe_lookup_decl (v, ctx);
+		  tree t;
+		  if (is_omp_target (ctx->stmt))
+		    t = NULL_TREE;
+		  else
+		    t = maybe_lookup_decl (v, ctx);
 		  if (t)
 		    v = t;
 		  else
@@ -5491,7 +5550,11 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
 				     TYPE_SIZE_UNIT (type));
 		  else
 		    {
-		      tree t = maybe_lookup_decl (v, ctx);
+		      tree t;
+		      if (is_omp_target (ctx->stmt))
+			t = NULL_TREE;
+		      else
+			t = maybe_lookup_decl (v, ctx);
 		      if (t)
 			v = t;
 		      else
@@ -5801,8 +5864,11 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
 	    }
 	  else if (pass == 2)
 	    {
-	      if (is_global_var (maybe_lookup_decl_in_outer_ctx (var, ctx)))
+	      tree out = maybe_lookup_decl_in_outer_ctx (var, ctx);
+	      if (is_global_var (out))
 		x = var;
+	      else if (is_omp_target (ctx->stmt))
+		x = out;
 	      else
 		{
 		  bool by_ref = use_pointer_for_field (var, ctx);
@@ -6736,7 +6802,27 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
 		  if (OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c))
 		    {
 		      tseq = OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c);
-		      lower_omp (&tseq, ctx);
+		      if (c_kind == OMP_CLAUSE_IN_REDUCTION
+			  && is_omp_target (ctx->stmt))
+			{
+			  tree d = maybe_lookup_decl_in_outer_ctx (var, ctx);
+			  tree oldv = NULL_TREE;
+			  gcc_assert (d);
+			  if (DECL_HAS_VALUE_EXPR_P (d))
+			    oldv = DECL_VALUE_EXPR (d);
+			  SET_DECL_VALUE_EXPR (d, new_vard);
+			  DECL_HAS_VALUE_EXPR_P (d) = 1;
+			  lower_omp (&tseq, ctx);
+			  if (oldv)
+			    SET_DECL_VALUE_EXPR (d, oldv);
+			  else
+			    {
+			      SET_DECL_VALUE_EXPR (d, NULL_TREE);
+			      DECL_HAS_VALUE_EXPR_P (d) = 0;
+			    }
+			}
+		      else
+			lower_omp (&tseq, ctx);
 		      gimple_seq_add_seq (ilist, tseq);
 		    }
 		  OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c) = NULL;
@@ -12658,11 +12744,26 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
   location_t loc = gimple_location (stmt);
   bool offloaded, data_region;
   unsigned int map_cnt = 0;
+  tree in_reduction_clauses = NULL_TREE;
 
   offloaded = is_gimple_omp_offloaded (stmt);
   switch (gimple_omp_target_kind (stmt))
     {
     case GF_OMP_TARGET_KIND_REGION:
+      tree *p, *q;
+      q = &in_reduction_clauses;
+      for (p = gimple_omp_target_clauses_ptr (stmt); *p; )
+	if (OMP_CLAUSE_CODE (*p) == OMP_CLAUSE_IN_REDUCTION)
+	  {
+	    *q = *p;
+	    q = &OMP_CLAUSE_CHAIN (*q);
+	    *p = OMP_CLAUSE_CHAIN (*p);
+	  }
+	else
+	  p = &OMP_CLAUSE_CHAIN (*p);
+      *q = NULL_TREE;
+      *p = in_reduction_clauses;
+      /* FALLTHRU */
     case GF_OMP_TARGET_KIND_UPDATE:
     case GF_OMP_TARGET_KIND_ENTER_DATA:
     case GF_OMP_TARGET_KIND_EXIT_DATA:
@@ -12690,12 +12791,17 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
 
   gimple_seq dep_ilist = NULL;
   gimple_seq dep_olist = NULL;
-  if (omp_find_clause (clauses, OMP_CLAUSE_DEPEND))
+  bool has_depend = omp_find_clause (clauses, OMP_CLAUSE_DEPEND) != NULL_TREE;
+  if (has_depend || in_reduction_clauses)
     {
       push_gimplify_context ();
       dep_bind = gimple_build_bind (NULL, NULL, make_node (BLOCK));
-      lower_depend_clauses (gimple_omp_target_clauses_ptr (stmt),
-			    &dep_ilist, &dep_olist);
+      if (has_depend)
+	lower_depend_clauses (gimple_omp_target_clauses_ptr (stmt),
+			      &dep_ilist, &dep_olist);
+      if (in_reduction_clauses)
+	lower_rec_input_clauses (in_reduction_clauses, &dep_ilist, &dep_olist,
+				 ctx, NULL);
     }
 
   tgt_bind = NULL;
@@ -12834,6 +12940,7 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
 	/* Don't remap compute constructs' reduction variables, because the
 	   intermediate result must be local to each gang.  */
 	if (offloaded && !(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+			   && is_gimple_omp_oacc (ctx->stmt)
 			   && OMP_CLAUSE_MAP_IN_REDUCTION (c)))
 	  {
 	    tree var_type = TREE_TYPE (var);
@@ -13085,16 +13192,46 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
 		if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
 		    && OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c))
 		  {
-		    gcc_checking_assert (OMP_CLAUSE_DECL (OMP_CLAUSE_CHAIN (c))
-					 == get_base_address (ovar));
 		    nc = OMP_CLAUSE_CHAIN (c);
+		    gcc_checking_assert (OMP_CLAUSE_DECL (nc)
+					 == get_base_address (ovar));
 		    ovar = OMP_CLAUSE_DECL (nc);
 		  }
 		else
 		  {
 		    tree x = build_sender_ref (c, ctx);
-		    tree v
-		      = build_fold_addr_expr_with_type (ovar, ptr_type_node);
+		    tree v = ovar;
+		    if (in_reduction_clauses
+			&& OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+			&& OMP_CLAUSE_MAP_IN_REDUCTION (c))
+		      {
+			v = unshare_expr (v);
+			tree *p = &v;
+			while (handled_component_p (*p)
+			       || TREE_CODE (*p) == INDIRECT_REF
+			       || TREE_CODE (*p) == ADDR_EXPR
+			       || TREE_CODE (*p) == MEM_REF
+			       || TREE_CODE (*p) == NON_LVALUE_EXPR)
+			  p = &TREE_OPERAND (*p, 0);
+			tree d = *p;
+			if (is_variable_sized (d))
+			  {
+			    gcc_assert (DECL_HAS_VALUE_EXPR_P (d));
+			    d = DECL_VALUE_EXPR (d);
+			    gcc_assert (TREE_CODE (d) == INDIRECT_REF);
+			    d = TREE_OPERAND (d, 0);
+			    gcc_assert (DECL_P (d));
+			  }
+			splay_tree_key key
+			  = (splay_tree_key) &DECL_CONTEXT (d);
+			tree nd = (tree) splay_tree_lookup (ctx->field_map,
+							    key)->value;
+			if (d == *p)
+			  *p = nd;
+			else
+			  *p = build_fold_indirect_ref (nd);
+		      }
+		    v = build_fold_addr_expr_with_type (v, ptr_type_node);
 		    gimplify_assign (x, v, &ilist);
 		    nc = NULL_TREE;
 		  }
@@ -13121,19 +13258,45 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
 	    if (DECL_P (ovar) && DECL_ALIGN_UNIT (ovar) > talign)
 	      talign = DECL_ALIGN_UNIT (ovar);
 
+	    var = NULL_TREE;
+	    if (nc)
+	      {
+		if (in_reduction_clauses
+		    && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+		    && OMP_CLAUSE_MAP_IN_REDUCTION (c))
+		  {
+		    tree d = ovar;
+		    if (is_variable_sized (d))
+		      {
+			gcc_assert (DECL_HAS_VALUE_EXPR_P (d));
+			d = DECL_VALUE_EXPR (d);
+			gcc_assert (TREE_CODE (d) == INDIRECT_REF);
+			d = TREE_OPERAND (d, 0);
+			gcc_assert (DECL_P (d));
+		      }
+		    splay_tree_key key
+		      = (splay_tree_key) &DECL_CONTEXT (d);
+		    tree nd = (tree) splay_tree_lookup (ctx->field_map,
+							key)->value;
+		    if (d == ovar)
+		      var = nd;
+		    else
+		      var = build_fold_indirect_ref (nd);
+		  }
+		else
+		  var = lookup_decl_in_outer_ctx (ovar, ctx);
+	      }
 	    if (nc
 		&& OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
 		&& (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH
 		    || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_DETACH)
 		&& is_omp_target (stmt))
 	      {
-		var = lookup_decl_in_outer_ctx (ovar, ctx);
 		x = build_sender_ref (c, ctx);
 		gimplify_assign (x, build_fold_addr_expr (var), &ilist);
 	      }
 	    else if (nc)
 	      {
-		var = lookup_decl_in_outer_ctx (ovar, ctx);
 		x = build_sender_ref (nc, ctx);
 
 		if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
diff --git a/gcc/testsuite/c-c++-common/gomp/clauses-1.c b/gcc/testsuite/c-c++-common/gomp/clauses-1.c
index 3a70a4f6180..378c7bf55a3 100644
--- a/gcc/testsuite/c-c++-common/gomp/clauses-1.c
+++ b/gcc/testsuite/c-c++-common/gomp/clauses-1.c
@@ -125,20 +125,20 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s,
   #pragma omp target parallel \
     device(d) map (tofrom: m) if (target: i1) private (p) firstprivate (f) defaultmap(tofrom: scalar) is_device_ptr (idp) \
     if (parallel: i2) default(shared) shared(s) reduction(+:r) num_threads (nth) proc_bind(spread) \
-    nowait depend(inout: dd[0]) allocate (omp_default_mem_alloc:f)
+    nowait depend(inout: dd[0]) allocate (omp_default_mem_alloc:f) in_reduction(+:r2)
     ;
   #pragma omp target parallel for \
     device(d) map (tofrom: m) if (target: i1) private (p) firstprivate (f) defaultmap(tofrom: scalar) is_device_ptr (idp) \
     if (parallel: i2) default(shared) shared(s) reduction(+:r) num_threads (nth) proc_bind(spread) \
     lastprivate (l) linear (ll:1) ordered schedule(static, 4) collapse(1) nowait depend(inout: dd[0]) \
-    allocate (omp_default_mem_alloc:f)
+    allocate (omp_default_mem_alloc:f) in_reduction(+:r2)
   for (int i = 0; i < 64; i++)
     ll++;
   #pragma omp target parallel for \
     device(d) map (tofrom: m) if (target: i1) private (p) firstprivate (f) defaultmap(tofrom: scalar) is_device_ptr (idp) \
     if (parallel: i2) default(shared) shared(s) reduction(+:r) num_threads (nth) proc_bind(spread) \
     lastprivate (l) linear (ll:1) schedule(static, 4) collapse(1) nowait depend(inout: dd[0]) order(concurrent) \
-    allocate (omp_default_mem_alloc:f)
+    allocate (omp_default_mem_alloc:f) in_reduction(+:r2)
   for (int i = 0; i < 64; i++)
     ll++;
   #pragma omp target parallel for simd \
@@ -146,18 +146,18 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s,
     if (parallel: i2) default(shared) shared(s) reduction(+:r) num_threads (nth) proc_bind(spread) \
     lastprivate (l) linear (ll:1) schedule(static, 4) collapse(1) \
     safelen(8) simdlen(4) aligned(q: 32) nowait depend(inout: dd[0]) nontemporal(ntm) if (simd: i3) order(concurrent) \
-    allocate (omp_default_mem_alloc:f)
+    allocate (omp_default_mem_alloc:f) in_reduction(+:r2)
   for (int i = 0; i < 64; i++)
     ll++;
   #pragma omp target teams \
     device(d) map (tofrom: m) if (target: i1) private (p) firstprivate (f) defaultmap(tofrom: scalar) is_device_ptr (idp) \
     shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) nowait depend(inout: dd[0]) \
-    allocate (omp_default_mem_alloc:f)
+    allocate (omp_default_mem_alloc:f) in_reduction(+:r2)
     ;
   #pragma omp target teams distribute \
     device(d) map (tofrom: m) if (target: i1) private (p) firstprivate (f) defaultmap(tofrom: scalar) is_device_ptr (idp) \
     shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) \
-    collapse(1) dist_schedule(static, 16) nowait depend(inout: dd[0]) allocate (omp_default_mem_alloc:f)
+    collapse(1) dist_schedule(static, 16) nowait depend(inout: dd[0]) allocate (omp_default_mem_alloc:f) in_reduction(+:r2)
   for (int i = 0; i < 64; i++)
     ;
   #pragma omp target teams distribute parallel for \
@@ -166,7 +166,7 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s,
     collapse(1) dist_schedule(static, 16) \
     if (parallel: i2) num_threads (nth) proc_bind(spread) \
     lastprivate (l) schedule(static, 4) nowait depend(inout: dd[0]) order(concurrent) \
-     allocate (omp_default_mem_alloc:f)
+     allocate (omp_default_mem_alloc:f) in_reduction(+:r2)
   for (int i = 0; i < 64; i++)
     ll++;
   #pragma omp target teams distribute parallel for simd \
@@ -176,7 +176,7 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s,
     if (parallel: i2) num_threads (nth) proc_bind(spread) \
     lastprivate (l) schedule(static, 4) order(concurrent) \
     safelen(8) simdlen(4) aligned(q: 32) nowait depend(inout: dd[0]) nontemporal(ntm) if (simd: i3) \
-    allocate (omp_default_mem_alloc:f)
+    allocate (omp_default_mem_alloc:f) in_reduction(+:r2)
   for (int i = 0; i < 64; i++)
     ll++;
   #pragma omp target teams distribute simd \
@@ -184,14 +184,14 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s,
     shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) \
     collapse(1) dist_schedule(static, 16) order(concurrent) \
     safelen(8) simdlen(4) aligned(q: 32) nowait depend(inout: dd[0]) nontemporal(ntm) \
-    allocate (omp_default_mem_alloc:f)
+    allocate (omp_default_mem_alloc:f) in_reduction(+:r2)
   for (int i = 0; i < 64; i++)
     ll++;
   #pragma omp target simd \
     device(d) map (tofrom: m) if (target: i1) private (p) firstprivate (f) defaultmap(tofrom: scalar) is_device_ptr (idp) \
     safelen(8) simdlen(4) lastprivate (l) linear(ll: 1) aligned(q: 32) reduction(+:r) \
     nowait depend(inout: dd[0]) nontemporal(ntm) if(simd:i3) order(concurrent) \
-    allocate (omp_default_mem_alloc:f)
+    allocate (omp_default_mem_alloc:f) in_reduction(+:r2)
   for (int i = 0; i < 64; i++)
     ll++;
   #pragma omp taskgroup task_reduction(+:r2) allocate (r2)
@@ -215,7 +215,7 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s,
     order(concurrent) allocate (f)
   for (int i = 0; i < 64; i++)
     ll++;
-  #pragma omp target nowait depend(inout: dd[0])
+  #pragma omp target nowait depend(inout: dd[0]) in_reduction(+:r2)
   #pragma omp teams distribute \
     private(p) firstprivate (f) shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) \
     collapse(1) dist_schedule(static, 16) allocate (omp_default_mem_alloc: f)
@@ -401,28 +401,28 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s,
     device(d) map (tofrom: m) if (target: i1) private (p) firstprivate (f) defaultmap(tofrom: scalar) is_device_ptr (idp) \
     if (parallel: i2) default(shared) shared(s) reduction(+:r) num_threads (nth) proc_bind(spread) \
     nowait depend(inout: dd[0]) lastprivate (l) bind(parallel) order(concurrent) collapse(1) \
-    allocate (omp_default_mem_alloc: f)
+    allocate (omp_default_mem_alloc: f) in_reduction(+:r2)
   for (l = 0; l < 64; ++l)
     ;
   #pragma omp target parallel loop \
     device(d) map (tofrom: m) if (target: i1) private (p) firstprivate (f) defaultmap(tofrom: scalar) is_device_ptr (idp) \
     if (parallel: i2) default(shared) shared(s) reduction(+:r) num_threads (nth) proc_bind(spread) \
     nowait depend(inout: dd[0]) lastprivate (l) order(concurrent) collapse(1) \
-    allocate (omp_default_mem_alloc: f)
+    allocate (omp_default_mem_alloc: f) in_reduction(+:r2)
   for (l = 0; l < 64; ++l)
     ;
   #pragma omp target teams loop \
     device(d) map (tofrom: m) if (target: i1) private (p) firstprivate (f) defaultmap(tofrom: scalar) is_device_ptr (idp) \
     shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) nowait depend(inout: dd[0]) \
     lastprivate (l) bind(teams) collapse(1) \
-    allocate (omp_default_mem_alloc: f)
+    allocate (omp_default_mem_alloc: f) in_reduction(+:r2)
   for (l = 0; l < 64; ++l)
     ;
   #pragma omp target teams loop \
     device(d) map (tofrom: m) if (target: i1) private (p) firstprivate (f) defaultmap(tofrom: scalar) is_device_ptr (idp) \
     shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) nowait depend(inout: dd[0]) \
     lastprivate (l) order(concurrent) collapse(1) \
-    allocate (omp_default_mem_alloc: f)
+    allocate (omp_default_mem_alloc: f) in_reduction(+:r2)
   for (l = 0; l < 64; ++l)
     ;
 }
diff --git a/gcc/testsuite/c-c++-common/gomp/target-in-reduction-1.c b/gcc/testsuite/c-c++-common/gomp/target-in-reduction-1.c
new file mode 100644
index 00000000000..23ed300d9e9
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/target-in-reduction-1.c
@@ -0,0 +1,12 @@
+void
+foo (int i, int j, int k)
+{
+  #pragma omp target in_reduction (+:i) private (i)	/* { dg-error "'i' appears more than once in data-sharing clauses" } */
+  ;
+  #pragma omp target private (i) in_reduction (+:i)	/* { dg-error "'i' appears both in data and map clauses" } */
+  ;
+  #pragma omp target in_reduction (+:i) firstprivate (i)	/* { dg-error "'i' appears more than once in data-sharing clauses" } */
+  ;								/* { dg-error "'i' appears both in data and map clauses" "" { target *-*-* } .-1 } */
+  #pragma omp target firstprivate (i) in_reduction (+:i)	/* { dg-error "'i' appears both in data and map clauses" } */
+  ;
+}
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index 51f4e538cf3..0790b5de938 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -1789,10 +1789,17 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,
 	    }
 	  dump_generic_node (pp, TREE_VALUE (node), spc, flags, false);
 	  node = TREE_CHAIN (node);
-	  if (node && TREE_CODE (node) == TREE_LIST)
+	  if (node)
 	    {
 	      pp_comma (pp);
 	      pp_space (pp);
+	      if (TREE_CODE (node) == TREE_LIST)
+		continue;
+	      else
+		{
+		  dump_generic_node (pp, node, spc, flags, false);
+		  break;
+		}
 	    }
 	}
       break;
diff --git a/gcc/tree.h b/gcc/tree.h
index 6ff4fa989ff..340f40e5f5e 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1675,7 +1675,8 @@ class auto_suppress_location_wrappers
 #define OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION(NODE) \
   TREE_PROTECTED (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP))
 /* Nonzero if this map clause is for an OpenACC compute construct's reduction
-   variable.  */
+   variable or OpenMP map clause mentioned also in in_reduction clause on the
+   same construct.  */
 #define OMP_CLAUSE_MAP_IN_REDUCTION(NODE) \
   TREE_PRIVATE (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP))
 
diff --git a/libgomp/testsuite/libgomp.c++/target-in-reduction-1.C b/libgomp/testsuite/libgomp.c++/target-in-reduction-1.C
new file mode 100644
index 00000000000..21130f5bb82
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/target-in-reduction-1.C
@@ -0,0 +1,113 @@
+void
+foo (int &x, int *&y, int n, int v)
+{
+  int zu[3] = { 45, 46, 47 };
+  int uu[n], wu[n], i;
+  int (&z)[3] = zu;
+  int (&u)[n] = uu;
+  int (&w)[n] = wu;
+  for (i = 0; i < n; i++)
+    w[i] = u[i] = n + i;
+  #pragma omp taskgroup task_reduction (+: x, y[:2], z[1:2], u, w[1:v])
+  {
+    #pragma omp task in_reduction (+: x, y[:2], z[1:2], u, w[1:v])
+    {
+      x++;
+      y[0] += 2;
+      y[1] += 3;
+      z[1] += 4;
+      u[0] += 5;
+      w[1] += 6;
+    }
+    #pragma omp target in_reduction (+: x, y[:2], z[1:2], u, w[1:v])
+    {
+      x += 4;
+      y[0] += 5;
+      y[1] += 6;
+      z[2] += 7;
+      u[1] += 8;
+      w[2] += 7;
+    }
+    #pragma omp target in_reduction (+: x, y[:v], z[1:v], u, w[1:2])
+    {
+      x += 9;
+      y[0] += 10;
+      y[1] += 11;
+      z[1] += 12;
+      u[2] += 13;
+      w[1] += 14;
+    }
+  }
+  if (x != 56 || y[0] != 60 || y[1] != 64)
+    __builtin_abort ();
+  if (z[0] != 45 || z[1] != 62 || z[2] != 54)
+    __builtin_abort ();
+  if (u[0] != 8 || u[1] != 12 || u[2] != 18)
+    __builtin_abort ();
+  if (w[0] != 3 || w[1] != 24 || w[2] != 12)
+    __builtin_abort ();
+}
+
+void
+bar (int &x, int *&y, int n, int v)
+{
+  int zu[3] = { 45, 46, 47 };
+  int uu[n], wu[n], i;
+  int (&z)[3] = zu;
+  int (&u)[n] = uu;
+  int (&w)[n] = wu;
+  for (i = 0; i < n; i++)
+    w[i] = u[i] = n + i;
+  #pragma omp parallel master
+  #pragma omp taskgroup task_reduction (+: x, y[:2], z[1:2], u, w[1:v])
+  {
+    #pragma omp task in_reduction (+: x, y[:2], z[1:2], u, w[1:v])
+    {
+      x++;
+      y[0] += 2;
+      y[1] += 3;
+      z[1] += 4;
+      u[0] += 5;
+      w[1] += 6;
+    }
+    #pragma omp target in_reduction (+: x, y[:2], z[1:2], u, w[1:v])
+    {
+      x += 4;
+      y[0] += 5;
+      y[1] += 6;
+      z[2] += 7;
+      u[1] += 8;
+      w[2] += 7;
+    }
+    #pragma omp target in_reduction (+: x, y[:v], z[1:v], u, w[1:2])
+    {
+      x += 9;
+      y[0] += 10;
+      y[1] += 11;
+      z[1] += 12;
+      u[2] += 13;
+      w[1] += 14;
+    }
+  }
+  if (x != 56 || y[0] != 77 || y[1] != 84)
+    __builtin_abort ();
+  if (z[0] != 45 || z[1] != 62 || z[2] != 54)
+    __builtin_abort ();
+  if (u[0] != 8 || u[1] != 12 || u[2] != 18)
+    __builtin_abort ();
+  if (w[0] != 3 || w[1] != 24 || w[2] != 12)
+    __builtin_abort ();
+}
+
+int
+main ()
+{
+  int x = 42;
+  int yu[2] = { 43, 44 };
+  int *y = yu;
+  #pragma omp parallel master
+  foo (x, y, 3, 2);
+  x = 42;
+  bar (x, y, 3, 2);
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c++/target-in-reduction-2.C b/libgomp/testsuite/libgomp.c++/target-in-reduction-2.C
new file mode 100644
index 00000000000..5da0e903b66
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/target-in-reduction-2.C
@@ -0,0 +1,182 @@
+struct S { int a, b, c[2]; };
+#pragma omp declare reduction (+: S : (omp_out.a += omp_in.a, omp_out.b += omp_in.b)) \
+  initializer (omp_priv = { 0, 0, { 0, 0 } })
+
+void
+foo (S &x, S *&y, int n, int v)
+{
+  S zu[3] = { { 45, 47, {} }, { 46, 48, {} }, { 47, 49, {} } };
+  S uu[n], wu[n];
+  S (&z)[3] = zu;
+  S (&u)[n] = uu;
+  S (&w)[n] = wu;
+  int i;
+  for (i = 0; i < n; i++)
+    {
+      w[i].a = u[i].a = n + i;
+      w[i].b = u[i].b = n - i;
+      w[i].c[0] = u[i].c[0] = 0;
+      w[i].c[1] = u[i].c[1] = 0;
+    }
+  #pragma omp taskgroup task_reduction (+: x, y[:2], z[1:2], u, w[1:v])
+  {
+    #pragma omp task in_reduction (+: x, y[:2], z[1:2], u, w[1:v])
+    {
+      x.a++;
+      x.b++;
+      y[0].a += 2;
+      y[0].b += 12;
+      y[1].a += 3;
+      y[1].b += 13;
+      z[1].a += 4;
+      z[1].b += 14;
+      u[0].a += 5;
+      u[0].b += 15;
+      w[1].a += 6;
+      w[1].b += 16;
+    }
+    #pragma omp target in_reduction (+: x, y[:2], z[1:2], u, w[1:v])
+    {
+      x.a += 4;
+      x.b += 14;
+      y[0].a += 5;
+      y[0].b += 15;
+      y[1].a += 6;
+      y[1].b += 16;
+      z[2].a += 7;
+      z[2].b += 17;
+      u[1].a += 8;
+      u[1].b += 18;
+      w[2].a += 7;
+      w[2].b += 17;
+    }
+    #pragma omp target in_reduction (+: x, y[:v], z[1:v], u, w[1:2])
+    {
+      x.a += 9;
+      x.b += 19;
+      y[0].a += 10;
+      y[0].b += 20;
+      y[1].a += 11;
+      y[1].b += 21;
+      z[1].a += 12;
+      z[1].b += 22;
+      u[2].a += 13;
+      u[2].b += 23;
+      w[1].a += 14;
+      w[1].b += 24;
+    }
+  }
+  if (x.a != 56 || y[0].a != 60 || y[1].a != 64)
+    __builtin_abort ();
+  if (x.b != 86 || y[0].b != 100 || y[1].b != 104)
+    __builtin_abort ();
+  if (z[0].a != 45 || z[1].a != 62 || z[2].a != 54)
+    __builtin_abort ();
+  if (z[0].b != 47 || z[1].b != 84 || z[2].b != 66)
+    __builtin_abort ();
+  if (u[0].a != 8 || u[1].a != 12 || u[2].a != 18)
+    __builtin_abort ();
+  if (u[0].b != 18 || u[1].b != 20 || u[2].b != 24)
+    __builtin_abort ();
+  if (w[0].a != 3 || w[1].a != 24 || w[2].a != 12)
+    __builtin_abort ();
+  if (w[0].b != 3 || w[1].b != 42 || w[2].b != 18)
+    __builtin_abort ();
+}
+
+void
+bar (S &x, S *&y, int n, int v)
+{
+  S zu[3] = { { 45, 47, {} }, { 46, 48, {} }, { 47, 49, {} } };
+  S uu[n], wu[n];
+  S (&z)[3] = zu;
+  S (&u)[n] = uu;
+  S (&w)[n] = wu;
+  int i;
+  for (i = 0; i < n; i++)
+    {
+      w[i].a = u[i].a = n + i;
+      w[i].b = u[i].b = n - i;
+      w[i].c[0] = u[i].c[0] = 0;
+      w[i].c[1] = u[i].c[1] = 0;
+    }
+  #pragma omp parallel master
+  #pragma omp taskgroup task_reduction (+: x, y[:2], z[1:2], u, w[1:v])
+  {
+    #pragma omp task in_reduction (+: x, y[:2], z[1:2], u, w[1:v])
+    {
+      x.a++;
+      x.b++;
+      y[0].a += 2;
+      y[0].b += 12;
+      y[1].a += 3;
+      y[1].b += 13;
+      z[1].a += 4;
+      z[1].b += 14;
+      u[0].a += 5;
+      u[0].b += 15;
+      w[1].a += 6;
+      w[1].b += 16;
+    }
+    #pragma omp target in_reduction (+: x, y[:2], z[1:2], u, w[1:v])
+    {
+      x.a += 4;
+      x.b += 14;
+      y[0].a += 5;
+      y[0].b += 15;
+      y[1].a += 6;
+      y[1].b += 16;
+      z[2].a += 7;
+      z[2].b += 17;
+      u[1].a += 8;
+      u[1].b += 18;
+      w[2].a += 7;
+      w[2].b += 17;
+    }
+    #pragma omp target in_reduction (+: x, y[:v], z[1:v], u, w[1:2])
+    {
+      x.a += 9;
+      x.b += 19;
+      y[0].a += 10;
+      y[0].b += 20;
+      y[1].a += 11;
+      y[1].b += 21;
+      z[1].a += 12;
+      z[1].b += 22;
+      u[2].a += 13;
+      u[2].b += 23;
+      w[1].a += 14;
+      w[1].b += 24;
+    }
+  }
+  if (x.a != 56 || y[0].a != 77 || y[1].a != 84)
+    __builtin_abort ();
+  if (x.b != 86 || y[0].b != 147 || y[1].b != 154)
+    __builtin_abort ();
+  if (z[0].a != 45 || z[1].a != 62 || z[2].a != 54)
+    __builtin_abort ();
+  if (z[0].b != 47 || z[1].b != 84 || z[2].b != 66)
+    __builtin_abort ();
+  if (u[0].a != 8 || u[1].a != 12 || u[2].a != 18)
+    __builtin_abort ();
+  if (u[0].b != 18 || u[1].b != 20 || u[2].b != 24)
+    __builtin_abort ();
+  if (w[0].a != 3 || w[1].a != 24 || w[2].a != 12)
+    __builtin_abort ();
+  if (w[0].b != 3 || w[1].b != 42 || w[2].b != 18)
+    __builtin_abort ();
+}
+
+int
+main ()
+{
+  S x = { 42, 52 };
+  S yu[2] = { { 43, 53 }, { 44, 54 } };
+  S *y = yu;
+  #pragma omp parallel master
+  foo (x, y, 3, 2);
+  x.a = 42;
+  x.b = 52;
+  bar (x, y, 3, 2);
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-in-reduction-1.c b/libgomp/testsuite/libgomp.c-c++-common/target-in-reduction-1.c
new file mode 100644
index 00000000000..813b5d95d3d
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/target-in-reduction-1.c
@@ -0,0 +1,104 @@
+void
+foo (int x, int *y, int n, int v)
+{
+  int z[3] = { 45, 46, 47 };
+  int u[n], w[n], i;
+  for (i = 0; i < n; i++)
+    w[i] = u[i] = n + i;
+  #pragma omp taskgroup task_reduction (+: x, y[:2], z[1:2], u, w[1:v])
+  {
+    #pragma omp task in_reduction (+: x, y[:2], z[1:2], u, w[1:v])
+    {
+      x++;
+      y[0] += 2;
+      y[1] += 3;
+      z[1] += 4;
+      u[0] += 5;
+      w[1] += 6;
+    }
+    #pragma omp target in_reduction (+: x, y[:2], z[1:2], u, w[1:v])
+    {
+      x += 4;
+      y[0] += 5;
+      y[1] += 6;
+      z[2] += 7;
+      u[1] += 8;
+      w[2] += 7;
+    }
+    #pragma omp target in_reduction (+: x, y[:v], z[1:v], u, w[1:2])
+    {
+      x += 9;
+      y[0] += 10;
+      y[1] += 11;
+      z[1] += 12;
+      u[2] += 13;
+      w[1] += 14;
+    }
+  }
+  if (x != 56 || y[0] != 60 || y[1] != 64)
+    __builtin_abort ();
+  if (z[0] != 45 || z[1] != 62 || z[2] != 54)
+    __builtin_abort ();
+  if (u[0] != 8 || u[1] != 12 || u[2] != 18)
+    __builtin_abort ();
+  if (w[0] != 3 || w[1] != 24 || w[2] != 12)
+    __builtin_abort ();
+}
+
+void
+bar (int x, int *y, int n, int v)
+{
+  int z[3] = { 45, 46, 47 };
+  int u[n], w[n], i;
+  for (i = 0; i < n; i++)
+    w[i] = u[i] = n + i;
+  #pragma omp parallel master
+  #pragma omp taskgroup task_reduction (+: x, y[:2], z[1:2], u, w[1:v])
+  {
+    #pragma omp task in_reduction (+: x, y[:2], z[1:2], u, w[1:v])
+    {
+      x++;
+      y[0] += 2;
+      y[1] += 3;
+      z[1] += 4;
+      u[0] += 5;
+      w[1] += 6;
+    }
+    #pragma omp target in_reduction (+: x, y[:2], z[1:2], u, w[1:v])
+    {
+      x += 4;
+      y[0] += 5;
+      y[1] += 6;
+      z[2] += 7;
+      u[1] += 8;
+      w[2] += 7;
+    }
+    #pragma omp target in_reduction (+: x, y[:v], z[1:v], u, w[1:2])
+    {
+      x += 9;
+      y[0] += 10;
+      y[1] += 11;
+      z[1] += 12;
+      u[2] += 13;
+      w[1] += 14;
+    }
+  }
+  if (x != 56 || y[0] != 77 || y[1] != 84)
+    __builtin_abort ();
+  if (z[0] != 45 || z[1] != 62 || z[2] != 54)
+    __builtin_abort ();
+  if (u[0] != 8 || u[1] != 12 || u[2] != 18)
+    __builtin_abort ();
+  if (w[0] != 3 || w[1] != 24 || w[2] != 12)
+    __builtin_abort ();
+}
+
+int
+main ()
+{
+  int y[2] = { 43, 44 };
+  #pragma omp parallel master
+  foo (42, y, 3, 2);
+  bar (42, y, 3, 2);
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-in-reduction-2.c b/libgomp/testsuite/libgomp.c-c++-common/target-in-reduction-2.c
new file mode 100644
index 00000000000..dd56965251b
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/target-in-reduction-2.c
@@ -0,0 +1,173 @@
+struct S { int a, b, c[2]; };
+#pragma omp declare reduction (+: struct S : (omp_out.a += omp_in.a, omp_out.b += omp_in.b)) \
+  initializer (omp_priv = { 0, 0, { 0, 0 } })
+
+void
+foo (struct S x, struct S *y, int n, int v)
+{
+  struct S z[3] = { { 45, 47, {} }, { 46, 48, {} }, { 47, 49, {} } };
+  struct S u[n], w[n];
+  int i;
+  for (i = 0; i < n; i++)
+    {
+      w[i].a = u[i].a = n + i;
+      w[i].b = u[i].b = n - i;
+      w[i].c[0] = u[i].c[0] = 0;
+      w[i].c[1] = u[i].c[1] = 0;
+    }
+  #pragma omp taskgroup task_reduction (+: x, y[:2], z[1:2], u, w[1:v])
+  {
+    #pragma omp task in_reduction (+: x, y[:2], z[1:2], u, w[1:v])
+    {
+      x.a++;
+      x.b++;
+      y[0].a += 2;
+      y[0].b += 12;
+      y[1].a += 3;
+      y[1].b += 13;
+      z[1].a += 4;
+      z[1].b += 14;
+      u[0].a += 5;
+      u[0].b += 15;
+      w[1].a += 6;
+      w[1].b += 16;
+    }
+    #pragma omp target in_reduction (+: x, y[:2], z[1:2], u, w[1:v]) map(tofrom: x.a, x.b, x.c[:2])
+    {
+      x.a += 4;
+      x.b += 14;
+      y[0].a += 5;
+      y[0].b += 15;
+      y[1].a += 6;
+      y[1].b += 16;
+      z[2].a += 7;
+      z[2].b += 17;
+      u[1].a += 8;
+      u[1].b += 18;
+      w[2].a += 7;
+      w[2].b += 17;
+    }
+    #pragma omp target in_reduction (+: x, y[:v], z[1:v], u, w[1:2])
+    {
+      x.a += 9;
+      x.b += 19;
+      y[0].a += 10;
+      y[0].b += 20;
+      y[1].a += 11;
+      y[1].b += 21;
+      z[1].a += 12;
+      z[1].b += 22;
+      u[2].a += 13;
+      u[2].b += 23;
+      w[1].a += 14;
+      w[1].b += 24;
+    }
+  }
+  if (x.a != 56 || y[0].a != 60 || y[1].a != 64)
+    __builtin_abort ();
+  if (x.b != 86 || y[0].b != 100 || y[1].b != 104)
+    __builtin_abort ();
+  if (z[0].a != 45 || z[1].a != 62 || z[2].a != 54)
+    __builtin_abort ();
+  if (z[0].b != 47 || z[1].b != 84 || z[2].b != 66)
+    __builtin_abort ();
+  if (u[0].a != 8 || u[1].a != 12 || u[2].a != 18)
+    __builtin_abort ();
+  if (u[0].b != 18 || u[1].b != 20 || u[2].b != 24)
+    __builtin_abort ();
+  if (w[0].a != 3 || w[1].a != 24 || w[2].a != 12)
+    __builtin_abort ();
+  if (w[0].b != 3 || w[1].b != 42 || w[2].b != 18)
+    __builtin_abort ();
+}
+
+void
+bar (struct S x, struct S *y, int n, int v)
+{
+  struct S z[3] = { { 45, 47, {} }, { 46, 48, {} }, { 47, 49, {} } };
+  struct S u[n], w[n];
+  int i;
+  for (i = 0; i < n; i++)
+    {
+      w[i].a = u[i].a = n + i;
+      w[i].b = u[i].b = n - i;
+      w[i].c[0] = u[i].c[0] = 0;
+      w[i].c[1] = u[i].c[1] = 0;
+    }
+  #pragma omp parallel master
+  #pragma omp taskgroup task_reduction (+: x, y[:2], z[1:2], u, w[1:v])
+  {
+    #pragma omp task in_reduction (+: x, y[:2], z[1:2], u, w[1:v])
+    {
+      x.a++;
+      x.b++;
+      y[0].a += 2;
+      y[0].b += 12;
+      y[1].a += 3;
+      y[1].b += 13;
+      z[1].a += 4;
+      z[1].b += 14;
+      u[0].a += 5;
+      u[0].b += 15;
+      w[1].a += 6;
+      w[1].b += 16;
+    }
+    #pragma omp target in_reduction (+: x, y[:2], z[1:2], u, w[1:v]) map(tofrom: x.a, x.b, x.c[:2])
+    {
+      x.a += 4;
+      x.b += 14;
+      y[0].a += 5;
+      y[0].b += 15;
+      y[1].a += 6;
+      y[1].b += 16;
+      z[2].a += 7;
+      z[2].b += 17;
+      u[1].a += 8;
+      u[1].b += 18;
+      w[2].a += 7;
+      w[2].b += 17;
+    }
+    #pragma omp target in_reduction (+: x, y[:v], z[1:v], u, w[1:2])
+    {
+      x.a += 9;
+      x.b += 19;
+      y[0].a += 10;
+      y[0].b += 20;
+      y[1].a += 11;
+      y[1].b += 21;
+      z[1].a += 12;
+      z[1].b += 22;
+      u[2].a += 13;
+      u[2].b += 23;
+      w[1].a += 14;
+      w[1].b += 24;
+    }
+  }
+  if (x.a != 56 || y[0].a != 77 || y[1].a != 84)
+    __builtin_abort ();
+  if (x.b != 86 || y[0].b != 147 || y[1].b != 154)
+    __builtin_abort ();
+  if (z[0].a != 45 || z[1].a != 62 || z[2].a != 54)
+    __builtin_abort ();
+  if (z[0].b != 47 || z[1].b != 84 || z[2].b != 66)
+    __builtin_abort ();
+  if (u[0].a != 8 || u[1].a != 12 || u[2].a != 18)
+    __builtin_abort ();
+  if (u[0].b != 18 || u[1].b != 20 || u[2].b != 24)
+    __builtin_abort ();
+  if (w[0].a != 3 || w[1].a != 24 || w[2].a != 12)
+    __builtin_abort ();
+  if (w[0].b != 3 || w[1].b != 42 || w[2].b != 18)
+    __builtin_abort ();
+}
+
+int
+main ()
+{
+  struct S x = { 42, 52 };
+  struct S y[2] = { { 43, 53 }, { 44, 54 } };
+  #pragma omp parallel master
+  foo (x, y, 3, 2);
+  bar (x, y, 3, 2);
+  return 0;
+}


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

only message in thread, other threads:[~2021-08-25 15:06 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-25 15:06 [gcc/devel/omp/gcc-11] openmp: in_reduction clause support on target construct Chung-Lin Tang

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