]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[og11] Rework indirect struct handling for OpenACC in gimplify.c
authorJulian Brown <julian@codesourcery.com>
Tue, 18 May 2021 17:22:56 +0000 (10:22 -0700)
committerKwok Cheung Yeung <kcy@codesourcery.com>
Tue, 21 Jun 2022 13:11:38 +0000 (14:11 +0100)
This patch reworks indirect struct handling in gimplify.c (i.e. for
struct components mapped with "mystruct->a[0:n]", "mystruct->b", etc.),
for OpenACC.  The key observation leading to these changes was that
component mappings of references-to-structures is already implemented
and working, and indirect struct component handling via a pointer can
work quite similarly.  That lets us remove some earlier, special-case
handling for mapping indirect struct component accesses for OpenACC,
which required the pointed-to struct to be manually mapped before the
indirect component mapping.

With this patch, you can map struct components directly (e.g. an array
slice "mystruct->a[0:n]") just like you can map a non-indirect struct
component slice ("mystruct.a[0:n]"). Both references-to-pointers (with
the former syntax) and references to structs (with the latter syntax)
work now.

For Fortran class pointers, we no longer re-use GOMP_MAP_TO_PSET for the
class metadata (the structure that points to the class data and vptr)
-- it is instead treated as any other struct.

For C++, the struct handling also works for class members ("this->foo"),
without having to explicitly map "this[:1]" first.

For OpenACC, we permit chained indirect component references
("mystruct->a->b[0:n]"), though only the last part of such mappings will
trigger an attach/detach operation.  To properly use such a construct
on the target, you must still manually map "mystruct->a[:1]" first --
but there's no need to map "mystruct[:1]" explicitly before that.

This version of the patch avoids altering code paths for OpenMP,
where possible.

2021-06-02  Julian Brown  <julian@codesourcery.com>

gcc/fortran/
* trans-openmp.cc (gfc_trans_omp_clauses): Don't create GOMP_MAP_TO_PSET
mappings for class metadata, nor GOMP_MAP_POINTER mappings for
POINTER_TYPE_P decls.

gcc/
* gimplify.cc (extract_base_bit_offset): Add BASE_IND and OPENMP
parameters.  Handle pointer-typed indirect references for OpenACC
alongside reference-typed ones.
(strip_components_and_deref, aggregate_base_p): New functions.
(build_struct_group): Add pointer type indirect ref handling,
including chained references, for OpenACC.  Also handle references to
structs for OpenACC.  Conditionalise bits for OpenMP only where
appropriate.
(gimplify_scan_omp_clauses): Rework pointer-type indirect structure
access handling to work more like the reference-typed handling for
OpenACC only.
* omp-low.cc (scan_sharing_clauses): Handle pointer-type indirect struct
references, and references to pointers to structs also.

gcc/testsuite/
* g++.dg/goacc/member-array-acc.C: New test.
* g++.dg/gomp/member-array-omp.C: New test.

libgomp/
* testsuite/libgomp.oacc-c-c++-common/deep-copy-15.c: New test.
* testsuite/libgomp.oacc-c-c++-common/deep-copy-16.c: New test.
* testsuite/libgomp.oacc-c++/deep-copy-17.C: New test.

12 files changed:
gcc/ChangeLog.omp
gcc/fortran/ChangeLog.omp
gcc/fortran/trans-openmp.cc
gcc/gimplify.cc
gcc/omp-low.cc
gcc/testsuite/ChangeLog.omp
gcc/testsuite/g++.dg/goacc/member-array-acc.C [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/member-array-omp.C [new file with mode: 0644]
libgomp/ChangeLog.omp
libgomp/testsuite/libgomp.oacc-c++/deep-copy-17.C [new file with mode: 0644]
libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-15.c [new file with mode: 0644]
libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-16.c [new file with mode: 0644]

index 40063208825d88f7dc5b4349dc927539bda17cb9..25914ac1cad972d8cad7dd97f61a1f020e0c869b 100644 (file)
@@ -1,3 +1,19 @@
+2021-06-02  Julian Brown  <julian@codesourcery.com>
+
+       * gimplify.cc (extract_base_bit_offset): Add BASE_IND and OPENMP
+       parameters.  Handle pointer-typed indirect references for OpenACC
+       alongside reference-typed ones.
+       (strip_components_and_deref, aggregate_base_p): New functions.
+       (build_struct_group): Add pointer type indirect ref handling,
+       including chained references, for OpenACC.  Also handle references to
+       structs for OpenACC.  Conditionalise bits for OpenMP only where
+       appropriate.
+       (gimplify_scan_omp_clauses): Rework pointer-type indirect structure
+       access handling to work more like the reference-typed handling for
+       OpenACC only.
+       * omp-low.cc (scan_sharing_clauses): Handle pointer-type indirect struct
+       references, and references to pointers to structs also.
+
 2021-06-02  Julian Brown  <julian@codesourcery.com>
 
        * gimplify.cc (insert_struct_comp_map): Refactor function into...
index 57e9d25090db93b97750b31f92c08585ade2cbe7..8b1a8ee006f074fa43ead360566e11c2847e083d 100644 (file)
@@ -1,3 +1,9 @@
+2021-06-02  Julian Brown  <julian@codesourcery.com>
+
+       * trans-openmp.cc (gfc_trans_omp_clauses): Don't create GOMP_MAP_TO_PSET
+       mappings for class metadata, nor GOMP_MAP_POINTER mappings for
+       POINTER_TYPE_P decls.
+
 2021-02-02  Chung-Lin Tang  <cltang@codesourcery.com>
 
        * openmp.cc (gfc_check_omp_requires): Fix REVERSE_OFFLOAD typo.
index ec9996af7def313a421eb4a212fbc30ac5541b0b..4525e4392ba7279287f09f4e5b2bf552e9c27d4a 100644 (file)
@@ -3099,30 +3099,16 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
                  tree present = gfc_omp_check_optional_argument (decl, true);
                  if (openacc && n->sym->ts.type == BT_CLASS)
                    {
-                     tree type = TREE_TYPE (decl);
                      if (n->sym->attr.optional)
                        sorry ("optional class parameter");
-                     if (POINTER_TYPE_P (type))
-                       {
-                         node4 = build_omp_clause (input_location,
-                                                   OMP_CLAUSE_MAP);
-                         OMP_CLAUSE_SET_MAP_KIND (node4, GOMP_MAP_POINTER);
-                         OMP_CLAUSE_DECL (node4) = decl;
-                         OMP_CLAUSE_SIZE (node4) = size_int (0);
-                         decl = build_fold_indirect_ref (decl);
-                       }
                      tree ptr = gfc_class_data_get (decl);
                      ptr = build_fold_indirect_ref (ptr);
                      OMP_CLAUSE_DECL (node) = ptr;
                      OMP_CLAUSE_SIZE (node) = gfc_class_vtab_size_get (decl);
                      node2 = build_omp_clause (input_location, OMP_CLAUSE_MAP);
-                     OMP_CLAUSE_SET_MAP_KIND (node2, GOMP_MAP_TO_PSET);
-                     OMP_CLAUSE_DECL (node2) = decl;
-                     OMP_CLAUSE_SIZE (node2) = TYPE_SIZE_UNIT (type);
-                     node3 = build_omp_clause (input_location, OMP_CLAUSE_MAP);
-                     OMP_CLAUSE_SET_MAP_KIND (node3, GOMP_MAP_ATTACH_DETACH);
-                     OMP_CLAUSE_DECL (node3) = gfc_class_data_get (decl);
-                     OMP_CLAUSE_SIZE (node3) = size_int (0);
+                     OMP_CLAUSE_SET_MAP_KIND (node2, GOMP_MAP_ATTACH_DETACH);
+                     OMP_CLAUSE_DECL (node2) = gfc_class_data_get (decl);
+                     OMP_CLAUSE_SIZE (node2) = size_int (0);
                      goto finalize_map_clause;
                    }
                  else if (POINTER_TYPE_P (TREE_TYPE (decl))
index 3c296b8974f9f2f64702719929345f81c8d3b247..ea0cc6f69f937bb1456916f99234313314413f95 100644 (file)
@@ -8807,8 +8807,9 @@ build_struct_comp_nodes (enum tree_code code, tree grp_start, tree grp_end,
    has array type, else return NULL.  */
 
 static tree
-extract_base_bit_offset (tree base, tree *base_ref, poly_int64 *bitposp,
-                        poly_offset_int *poffsetp, tree *offsetp)
+extract_base_bit_offset (tree base, tree *base_ind, tree *base_ref,
+                        poly_int64 *bitposp, poly_offset_int *poffsetp,
+                        tree *offsetp, bool openmp)
 {
   tree offset;
   poly_int64 bitsize, bitpos;
@@ -8816,6 +8817,9 @@ extract_base_bit_offset (tree base, tree *base_ref, poly_int64 *bitposp,
   int unsignedp, reversep, volatilep = 0;
   poly_offset_int poffset;
 
+  if (base_ind)
+    *base_ind = NULL_TREE;
+
   if (base_ref)
     *base_ref = NULL_TREE;
 
@@ -8836,14 +8840,29 @@ extract_base_bit_offset (tree base, tree *base_ref, poly_int64 *bitposp,
   base = get_inner_reference (base, &bitsize, &bitpos, &offset, &mode,
                              &unsignedp, &reversep, &volatilep);
 
-  tree orig_base = base;
-
+  if (!openmp
+      && (TREE_CODE (base) == INDIRECT_REF
+         || (TREE_CODE (base) == MEM_REF
+             && integer_zerop (TREE_OPERAND (base, 1))))
+      && TREE_CODE (TREE_TYPE (TREE_OPERAND (base, 0))) == POINTER_TYPE)
+    {
+      if (base_ind)
+       *base_ind = base;
+      base = TREE_OPERAND (base, 0);
+    }
   if ((TREE_CODE (base) == INDIRECT_REF
        || (TREE_CODE (base) == MEM_REF
           && integer_zerop (TREE_OPERAND (base, 1))))
       && DECL_P (TREE_OPERAND (base, 0))
       && TREE_CODE (TREE_TYPE (TREE_OPERAND (base, 0))) == REFERENCE_TYPE)
-    base = TREE_OPERAND (base, 0);
+    {
+      if (base_ref)
+       *base_ref = base;
+      base = TREE_OPERAND (base, 0);
+    }
+
+  if (!openmp)
+    STRIP_NOPS (base);
 
   if (offset && poly_int_tree_p (offset))
     {
@@ -8860,10 +8879,6 @@ extract_base_bit_offset (tree base, tree *base_ref, poly_int64 *bitposp,
   *poffsetp = poffset;
   *offsetp = offset;
 
-  /* Set *BASE_REF if BASE was a dereferenced reference variable.  */
-  if (base_ref && orig_base != base)
-    *base_ref = orig_base;
-
   return base;
 }
 
@@ -8890,6 +8905,48 @@ is_or_contains_p (tree expr, tree base_ptr)
   return operand_equal_p (expr, base_ptr);
 }
 
+/* Remove COMPONENT_REFS and indirections from EXPR.  */
+
+static tree
+strip_components_and_deref (tree expr)
+{
+  while (TREE_CODE (expr) == COMPONENT_REF
+        || TREE_CODE (expr) == INDIRECT_REF
+        || (TREE_CODE (expr) == MEM_REF
+            && integer_zerop (TREE_OPERAND (expr, 1))))
+    expr = TREE_OPERAND (expr, 0);
+
+  return expr;
+}
+
+/* Return TRUE if EXPR is something we will use as the base of an aggregate
+   access, either:
+
+  - a DECL_P.
+  - a struct component with no indirection ("a.b.c").
+  - a struct component with indirection ("a->b->c").
+*/
+
+static bool
+aggregate_base_p (tree expr)
+{
+  while (TREE_CODE (expr) == COMPONENT_REF
+        && (DECL_P (TREE_OPERAND (expr, 0))
+            || (TREE_CODE (TREE_OPERAND (expr, 0)) == COMPONENT_REF)))
+    expr = TREE_OPERAND (expr, 0);
+
+  if (DECL_P (expr))
+    return true;
+
+  if (TREE_CODE (expr) == COMPONENT_REF
+      && (TREE_CODE (TREE_OPERAND (expr, 0)) == INDIRECT_REF
+         || (TREE_CODE (TREE_OPERAND (expr, 0)) == MEM_REF
+             && integer_zerop (TREE_OPERAND (TREE_OPERAND (expr, 0), 1)))))
+    return true;
+
+  return false;
+}
+
 /* Implement OpenMP 5.x map ordering rules for target directives. There are
    several rules, and with some level of ambiguity, hopefully we can at least
    collect the complexity here in one place.  */
@@ -9355,10 +9412,12 @@ build_struct_group (struct gimplify_omp_ctx *ctx,
 {
   poly_offset_int coffset;
   poly_int64 cbitpos;
-  tree base_ref, tree_coffset;
+  tree base_ind, base_ref, tree_coffset;
+  bool openmp = !(region_type & ORT_ACC);
 
-  tree base = extract_base_bit_offset (OMP_CLAUSE_DECL (c), &base_ref,
-                                      &cbitpos, &coffset, &tree_coffset);
+  tree base = extract_base_bit_offset (OMP_CLAUSE_DECL (c), &base_ind,
+                                      &base_ref, &cbitpos, &coffset,
+                                      &tree_coffset, openmp);
 
   bool do_map_struct = (base == decl && !tree_coffset);
 
@@ -9397,12 +9456,7 @@ build_struct_group (struct gimplify_omp_ctx *ctx,
     return NULL_TREE;
 
   /* Nor for attach_detach for OpenMP.  */
-  if ((code == OMP_TARGET
-       || code == OMP_TARGET_DATA
-       || code == OMP_TARGET_UPDATE
-       || code == OMP_TARGET_ENTER_DATA
-       || code == OMP_TARGET_EXIT_DATA)
-      && attach_detach)
+  if (openmp && attach_detach)
     {
       if (DECL_P (decl))
        {
@@ -9425,12 +9479,15 @@ build_struct_group (struct gimplify_omp_ctx *ctx,
 
       OMP_CLAUSE_SET_MAP_KIND (l, k);
 
-      if (base_ref)
+      if (!openmp && base_ind)
+       OMP_CLAUSE_DECL (l) = unshare_expr (base_ind);
+      else if (base_ref)
        OMP_CLAUSE_DECL (l) = unshare_expr (base_ref);
       else
        {
          OMP_CLAUSE_DECL (l) = unshare_expr (decl);
-         if (!DECL_P (OMP_CLAUSE_DECL (l))
+         if (openmp
+             && !DECL_P (OMP_CLAUSE_DECL (l))
              && (gimplify_expr (&OMP_CLAUSE_DECL (l), pre_p, NULL,
                                 is_gimple_lvalue, fb_lvalue) == GS_ERROR))
            return error_mark_node;
@@ -9486,6 +9543,48 @@ build_struct_group (struct gimplify_omp_ctx *ctx,
          OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (l);
          OMP_CLAUSE_CHAIN (l) = c2;
        }
+      else if (!openmp
+              && (base_ind || base_ref)
+              && (region_type & ORT_TARGET))
+       {
+         tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP);
+         enum gomp_map_kind mkind = base_ref ? GOMP_MAP_FIRSTPRIVATE_REFERENCE
+                                             : GOMP_MAP_FIRSTPRIVATE_POINTER;
+         OMP_CLAUSE_SET_MAP_KIND (c2, mkind);
+         OMP_CLAUSE_SIZE (c2) = size_zero_node;
+         tree sdecl = strip_components_and_deref (decl);
+         if (DECL_P (decl)
+             && (POINTER_TYPE_P (TREE_TYPE (sdecl))
+                 || TREE_CODE (TREE_TYPE (sdecl)) == REFERENCE_TYPE))
+           {
+             /* Insert after struct node.  */
+             OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (l);
+             OMP_CLAUSE_DECL (c2) = decl;
+             OMP_CLAUSE_CHAIN (l) = c2;
+           }
+         else
+           {
+             /* If the ultimate base for this component access is not a
+                pointer or reference, that means it is a struct component
+                access itself.  Insert a node to be processed on the next
+                iteration of our caller's loop, which will subsequently be
+                turned into a new GOMP_MAP_STRUCT mapping itself.
+
+                We need to do this else the non-DECL_P base won't be
+                rewritten correctly in the offloaded region.  */
+             tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c),
+                                         OMP_CLAUSE_MAP);
+             OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_FORCE_PRESENT);
+             OMP_CLAUSE_DECL (c2) = unshare_expr (decl);
+             OMP_CLAUSE_SIZE (c2) = (DECL_P (decl)
+                                     ? DECL_SIZE_UNIT (decl)
+                                     : TYPE_SIZE_UNIT (TREE_TYPE (decl)));
+             tree *next_node = &OMP_CLAUSE_CHAIN (*list_p);
+             OMP_CLAUSE_CHAIN (c2) = *next_node;
+             *next_node = c2;
+             return NULL_TREE;
+           }
+       }
       *flags = GOVD_MAP | GOVD_EXPLICIT;
       if (GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)) || ptr || attach_detach)
        *flags |= GOVD_SEEN;
@@ -9494,7 +9593,8 @@ build_struct_group (struct gimplify_omp_ctx *ctx,
 
       /* If this is a *pointer-to-struct expression, make sure a
         firstprivate map of the base-pointer exists.  */
-      if (component_ref_p
+      if (openmp
+         && component_ref_p
          && ((TREE_CODE (decl) == MEM_REF
               && integer_zerop (TREE_OPERAND (decl, 1)))
              || INDIRECT_REF_P (decl))
@@ -9524,10 +9624,12 @@ build_struct_group (struct gimplify_omp_ctx *ctx,
        n->value |= GOVD_SEEN;
       sc = &OMP_CLAUSE_CHAIN (*osc);
       /* The struct mapping might be immediately followed by a
-        FIRSTPRIVATE_REFERENCE if it is a reference.  (This added node is
-        removed in omp-low.c after it has been processed there.)  */
+        FIRSTPRIVATE_POINTER and/or FIRSTPRIVATE_REFERENCE -- if it's an
+        indirect access or a reference, or both.  (This added node is removed
+        in omp-low.c after it has been processed there.)  */
       if (*sc != c
-         && OMP_CLAUSE_MAP_KIND (*sc) == GOMP_MAP_FIRSTPRIVATE_REFERENCE)
+         && (OMP_CLAUSE_MAP_KIND (*sc) == GOMP_MAP_FIRSTPRIVATE_POINTER
+             || OMP_CLAUSE_MAP_KIND (*sc) == GOMP_MAP_FIRSTPRIVATE_REFERENCE))
        sc = &OMP_CLAUSE_CHAIN (*sc);
       for (; *sc != c; sc = &OMP_CLAUSE_CHAIN (*sc))
        if ((ptr || attach_detach) && sc == prev_list_p)
@@ -9542,9 +9644,10 @@ build_struct_group (struct gimplify_omp_ctx *ctx,
            poly_offset_int offset;
            poly_int64 bitpos;
            tree tree_offset;
-           tree base = extract_base_bit_offset (sc_decl, NULL, &bitpos,
-                                                &offset, &tree_offset);
-           if (base != decl)
+           tree base = extract_base_bit_offset (sc_decl, NULL, NULL,
+                                                &bitpos, &offset,
+                                                &tree_offset, openmp);
+           if (!base || !operand_equal_p (base, decl, 0))
              break;
            if (scp)
              continue;
@@ -9665,8 +9768,9 @@ build_struct_group (struct gimplify_omp_ctx *ctx,
        }
       else if (*sc != c)
        {
-         if (gimplify_expr (pd, pre_p, NULL, is_gimple_lvalue, fb_lvalue)
-             == GS_ERROR)
+         if (openmp
+             && (gimplify_expr (pd, pre_p, NULL, is_gimple_lvalue, fb_lvalue)
+                 == GS_ERROR))
            return error_mark_node;
          /* In the non-pointer case, the mapping clause itself is moved into
             the correct position in the struct component list, which in this
@@ -10231,10 +10335,43 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
              tree indir_base = NULL_TREE;
              tree orig_decl = decl;
              tree decl_ref = NULL_TREE;
-             if ((region_type & (ORT_ACC | ORT_TARGET | ORT_TARGET_DATA)) != 0
-                 && TREE_CODE (*pd) == COMPONENT_REF
-                 && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH
-                 && code != OACC_UPDATE)
+             if ((region_type & ORT_ACC) && TREE_CODE (decl) == COMPONENT_REF)
+               {
+                 /* Strip off component refs from RHS of e.g. "a->b->c.d.e"
+                    (which would leave "a->b" in that case).  This is intended
+                    to be equivalent to the base finding done by
+                    get_inner_reference.  */
+                 while (TREE_CODE (decl) == COMPONENT_REF
+                        && (DECL_P (TREE_OPERAND (decl, 0))
+                            || (TREE_CODE (TREE_OPERAND (decl, 0))
+                                == COMPONENT_REF)))
+                   decl = TREE_OPERAND (decl, 0);
+
+                 if (TREE_CODE (decl) == COMPONENT_REF)
+                   decl = TREE_OPERAND (decl, 0);
+
+                 /* Strip off RHS from "a->b".  */
+                 if ((TREE_CODE (decl) == INDIRECT_REF
+                      || (TREE_CODE (decl) == MEM_REF
+                          && integer_zerop (TREE_OPERAND (decl, 1))))
+                     && (TREE_CODE (TREE_TYPE (TREE_OPERAND (decl, 0)))
+                         == POINTER_TYPE))
+                   decl = TREE_OPERAND (decl, 0);
+
+                 /* Strip off RHS from "a_ref.b" (where a_ref is
+                    reference-typed).  */
+                 if (TREE_CODE (decl) == INDIRECT_REF
+                     && DECL_P (TREE_OPERAND (decl, 0))
+                     && (TREE_CODE (TREE_TYPE (TREE_OPERAND (decl, 0)))
+                         == REFERENCE_TYPE))
+                   decl = TREE_OPERAND (decl, 0);
+
+                 STRIP_NOPS (decl);
+               }
+             else if ((region_type & (ORT_TARGET | ORT_TARGET_DATA)) != 0
+                      && TREE_CODE (*pd) == COMPONENT_REF
+                      && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH
+                      && code != OACC_UPDATE)
                {
                  while (TREE_CODE (decl) == COMPONENT_REF)
                    {
@@ -10340,11 +10477,13 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
              if (code == OACC_UPDATE
                  && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH)
                OMP_CLAUSE_SET_MAP_KIND (c, GOMP_MAP_ALWAYS_POINTER);
-             if ((DECL_P (decl)
-                  || (component_ref_p
-                      && (INDIRECT_REF_P (decl)
-                          || TREE_CODE (decl) == MEM_REF
-                          || TREE_CODE (decl) == ARRAY_REF)))
+             if ((((region_type & ORT_ACC) && aggregate_base_p (decl))
+                  || (!(region_type & ORT_ACC)
+                      && (DECL_P (decl)
+                          || (component_ref_p
+                              && (INDIRECT_REF_P (decl)
+                                  || TREE_CODE (decl) == MEM_REF
+                                  || TREE_CODE (decl) == ARRAY_REF)))))
                  && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_TO_PSET
                  && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_ATTACH
                  && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_DETACH
index 52a894355f3a5561efdabe2dec0f96746006d428..fe1582baad648780cef3384217f6b831b5f269eb 100644 (file)
@@ -1749,8 +1749,10 @@ scan_sharing_clauses (tree clauses, omp_context *ctx,
              if (TREE_CODE (decl) == COMPONENT_REF
                  || (TREE_CODE (decl) == INDIRECT_REF
                      && TREE_CODE (TREE_OPERAND (decl, 0)) == COMPONENT_REF
-                     && (TREE_CODE (TREE_TYPE (TREE_OPERAND (decl, 0)))
-                         == REFERENCE_TYPE)))
+                     && (((TREE_CODE (TREE_TYPE (TREE_OPERAND (decl, 0)))
+                           == REFERENCE_TYPE)
+                          || (TREE_CODE (TREE_TYPE (TREE_OPERAND (decl, 0)))
+                              == POINTER_TYPE)))))
                break;
              if (DECL_SIZE (decl)
                  && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
@@ -14368,6 +14370,7 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
                if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_REFERENCE)
                  is_ref = false;
                bool ref_to_array = false;
+               bool ref_to_ptr = false;
                if (is_ref)
                  {
                    type = TREE_TYPE (type);
@@ -14386,6 +14389,12 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
                    new_var = decl2;
                    type = TREE_TYPE (new_var);
                  }
+               else if (TREE_CODE (type) == REFERENCE_TYPE
+                        && TREE_CODE (TREE_TYPE (type)) == POINTER_TYPE)
+                 {
+                   type = TREE_TYPE (type);
+                   ref_to_ptr = true;
+                 }
                x = build_receiver_ref (prev, false, ctx);
                x = fold_convert_loc (clause_loc, type, x);
                if (!integer_zerop (OMP_CLAUSE_SIZE (c)))
@@ -14408,7 +14417,8 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
                if (ref_to_array)
                  x = fold_convert_loc (clause_loc, TREE_TYPE (new_var), x);
                gimplify_expr (&x, &new_body, NULL, is_gimple_val, fb_rvalue);
-               if (is_ref && !ref_to_array)
+               if ((is_ref && !ref_to_array)
+                   || ref_to_ptr)
                  {
                    tree t = create_tmp_var_raw (type, get_name (var));
                    gimple_add_tmp_var (t);
index 79c519dbf1c4ccc8f8d22fbb5a7a21b0e583b8b3..bd35a67a64db6a464409e069b7deedc3b774e7c8 100644 (file)
@@ -1,3 +1,8 @@
+2021-06-02  Julian Brown  <julian@codesourcery.com>
+
+       * g++.dg/goacc/member-array-acc.C: New test.
+       * g++.dg/gomp/member-array-omp.C: New test.
+
 2021-05-14  Tobias Burnus  <tobias@codesourcery.com>
 
        * c-c++-common/gomp/map-6.c: Remove two dg-error.
diff --git a/gcc/testsuite/g++.dg/goacc/member-array-acc.C b/gcc/testsuite/g++.dg/goacc/member-array-acc.C
new file mode 100644 (file)
index 0000000..e0c1157
--- /dev/null
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fdump-tree-gimple" } */
+
+struct Foo {
+  float *a;
+  void init(int N) {
+    a = new float[N];
+    #pragma acc enter data create(a[0:N])
+  }
+};
+int main() { Foo x; x.init(1024); }
+
+/* { dg-final { scan-tree-dump {struct:\*\(struct Foo \*\) this \[len: 1\]\) map\(alloc:\(\(struct Foo \*\) this\)->a \[len: [0-9]+\]\) map\(alloc:\*_[0-9]+ \[len: _[0-9]+\]\) map\(attach:\(\(struct Foo \*\) this\)->a \[bias: 0\]\)} "gimple" } } */
diff --git a/gcc/testsuite/g++.dg/gomp/member-array-omp.C b/gcc/testsuite/g++.dg/gomp/member-array-omp.C
new file mode 100644 (file)
index 0000000..a53aa44
--- /dev/null
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fdump-tree-gimple" } */
+
+struct Foo {
+  float *a;
+  void init(int N) {
+    a = new float[N];
+    #pragma omp target enter data map(alloc:a[0:N])
+  }
+};
+int main() { Foo x; x.init(1024); }
+
+/* { dg-final { scan-tree-dump {map\(alloc:\*_[0-9]+ \[len: _[0-9]+\]\) map\(attach:this->a \[bias: 0\]\)} "gimple" } } */
index 6e7fc0d4abca26b9c798bcfd977c2ed172525fee..aed8dc03211f9f87cdc81bb97eb810f74cb4ff92 100644 (file)
@@ -1,3 +1,9 @@
+2021-06-02  Julian Brown  <julian@codesourcery.com>
+
+       * testsuite/libgomp.oacc-c-c++-common/deep-copy-15.c: New test.
+       * testsuite/libgomp.oacc-c-c++-common/deep-copy-16.c: New test.
+       * testsuite/libgomp.oacc-c++/deep-copy-17.C: New test.
+
 2021-03-25  Thomas Schwinge  <thomas@codesourcery.com>
 
        * target.c (__requires_mask_table, __requires_mask_table_end): Add
diff --git a/libgomp/testsuite/libgomp.oacc-c++/deep-copy-17.C b/libgomp/testsuite/libgomp.oacc-c++/deep-copy-17.C
new file mode 100644 (file)
index 0000000..dacbb52
--- /dev/null
@@ -0,0 +1,101 @@
+#include <cassert>
+
+/* Test attach/detach operation with pointers and references to structs.  */
+
+typedef struct mystruct {
+  int *a;
+  int b;
+  int *c;
+  int d;
+  int *e;
+} mystruct;
+
+void str (void)
+{
+  int a[10], c[10], e[10];
+  mystruct m = { .a = a, .c = c, .e = e };
+  a[0] = 5;
+  c[0] = 7;
+  e[0] = 9;
+  #pragma acc parallel copy(m.a[0:10], m.b, m.c[0:10], m.d, m.e[0:10])
+  {
+    m.a[0] = m.c[0] + m.e[0];
+  }
+  assert (m.a[0] == 7 + 9);
+}
+
+void strp (void)
+{
+  int *a = new int[10];
+  int *c = new int[10];
+  int *e = new int[10];
+  mystruct *m = new mystruct;
+  m->a = a;
+  m->c = c;
+  m->e = e;
+  a[0] = 6;
+  c[0] = 8;
+  e[0] = 10;
+  #pragma acc parallel copy(m->a[0:10], m->b, m->c[0:10], m->d, m->e[0:10])
+  {
+    m->a[0] = m->c[0] + m->e[0];
+  }
+  assert (m->a[0] == 8 + 10);
+  delete m;
+  delete[] a;
+  delete[] c;
+  delete[] e;
+}
+
+void strr (void)
+{
+  int *a = new int[10];
+  int *c = new int[10];
+  int *e = new int[10];
+  mystruct m;
+  mystruct &n = m;
+  n.a = a;
+  n.c = c;
+  n.e = e;
+  a[0] = 7;
+  c[0] = 9;
+  e[0] = 11;
+  #pragma acc parallel copy(n.a[0:10], n.b, n.c[0:10], n.d, n.e[0:10])
+  {
+    n.a[0] = n.c[0] + n.e[0];
+  }
+  assert (n.a[0] == 9 + 11);
+  delete[] a;
+  delete[] c;
+  delete[] e;
+}
+
+void strrp (void)
+{
+  int a[10], c[10], e[10];
+  mystruct *m = new mystruct;
+  mystruct *&n = m;
+  n->a = a;
+  n->b = 3;
+  n->c = c;
+  n->d = 5;
+  n->e = e;
+  a[0] = 8;
+  c[0] = 10;
+  e[0] = 12;
+  #pragma acc parallel copy(n->a[0:10], n->c[0:10], n->e[0:10])
+  {
+    n->a[0] = n->c[0] + n->e[0];
+  }
+  assert (n->a[0] == 10 + 12);
+  delete m;
+}
+
+int main (int argc, char *argv[])
+{
+  str ();
+  strp ();
+  strr ();
+  strrp ();
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-15.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-15.c
new file mode 100644 (file)
index 0000000..27fe1a9
--- /dev/null
@@ -0,0 +1,68 @@
+#include <stdlib.h>
+
+/* Test multiple struct dereferences on one directive, and slices starting at
+   non-zero.  */
+
+typedef struct {
+  int *a;
+  int *b;
+  int *c;
+} mystruct;
+
+int main(int argc, char* argv[])
+{
+  const int N = 1024;
+  mystruct *m = (mystruct *) malloc (sizeof (*m));
+  int i;
+
+  m->a = (int *) malloc (N * sizeof (int));
+  m->b = (int *) malloc (N * sizeof (int));
+  m->c = (int *) malloc (N * sizeof (int));
+
+  for (i = 0; i < N; i++)
+    {
+      m->a[i] = 0;
+      m->b[i] = 0;
+      m->c[i] = 0;
+    }
+
+  for (int i = 0; i < 99; i++)
+    {
+      int j;
+#pragma acc parallel loop copy(m->a[0:N])
+      for (j = 0; j < N; j++)
+       m->a[j]++;
+#pragma acc parallel loop copy(m->b[0:N], m->c[5:N-10])
+      for (j = 0; j < N; j++)
+       {
+         m->b[j]++;
+         if (j > 5 && j < N - 5)
+           m->c[j]++;
+       }
+    }
+
+  for (i = 0; i < N; i++)
+    {
+      if (m->a[i] != 99)
+       abort ();
+      if (m->b[i] != 99)
+       abort ();
+      if (i > 5 && i < N-5)
+       {
+         if (m->c[i] != 99)
+           abort ();
+       }
+      else
+       {
+         if (m->c[i] != 0)
+           abort ();
+       }
+    }
+
+  free (m->a);
+  free (m->b);
+  free (m->c);
+  free (m);
+
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-16.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-16.c
new file mode 100644 (file)
index 0000000..a7308e8
--- /dev/null
@@ -0,0 +1,231 @@
+#include <stdlib.h>
+
+/* Test mapping chained indirect struct accesses, mixed in different ways.  */
+
+typedef struct {
+  int *a;
+  int b;
+  int *c;
+} str1;
+
+typedef struct {
+  int d;
+  int *e;
+  str1 *f;
+} str2;
+
+typedef struct {
+  int g;
+  int h;
+  str2 *s2;
+} str3;
+
+typedef struct {
+  str3 m;
+  str3 n;
+} str4;
+
+void
+zero_arrays (str4 *s, int N)
+{
+  for (int i = 0; i < N; i++)
+    {
+      s->m.s2->e[i] = 0;
+      s->m.s2->f->a[i] = 0;
+      s->m.s2->f->c[i] = 0;
+      s->n.s2->e[i] = 0;
+      s->n.s2->f->a[i] = 0;
+      s->n.s2->f->c[i] = 0;
+    }
+}
+
+void
+alloc_s2 (str2 **s, int N)
+{
+  (*s) = (str2 *) malloc (sizeof (str2));
+  (*s)->f = (str1 *) malloc (sizeof (str1));
+  (*s)->e = (int *) malloc (sizeof (int) * N);
+  (*s)->f->a = (int *) malloc (sizeof (int) * N);
+  (*s)->f->c = (int *) malloc (sizeof (int) * N);
+}
+
+int main (int argc, char* argv[])
+{
+  const int N = 1024;
+  str4 p, *q;
+  int i;
+
+  alloc_s2 (&p.m.s2, N);
+  alloc_s2 (&p.n.s2, N);
+  q = (str4 *) malloc (sizeof (str4));
+  alloc_s2 (&q->m.s2, N);
+  alloc_s2 (&q->n.s2, N);
+
+  zero_arrays (&p, N);
+
+  for (int i = 0; i < 99; i++)
+    {
+#pragma acc enter data copyin(p.m.s2[:1])
+#pragma acc parallel loop copy(p.m.s2->e[:N])
+      for (int j = 0; j < N; j++)
+       p.m.s2->e[j]++;
+#pragma acc exit data delete(p.m.s2[:1])
+    }
+
+  for (i = 0; i < N; i++)
+    if (p.m.s2->e[i] != 99)
+      abort ();
+
+  zero_arrays (&p, N);
+
+  for (int i = 0; i < 99; i++)
+    {
+#pragma acc enter data copyin(p.m.s2[:1])
+#pragma acc enter data copyin(p.m.s2->f[:1])
+#pragma acc parallel loop copy(p.m.s2->f->a[:N]) copy(p.m.s2->f->c[:N])
+       for (int j = 0; j < N; j++)
+         {
+           p.m.s2->f->a[j]++;
+           p.m.s2->f->c[j]++;
+         }
+#pragma acc exit data delete(p.m.s2->f[:1])
+#pragma acc exit data delete(p.m.s2[:1])
+    }
+
+  for (i = 0; i < N; i++)
+    if (p.m.s2->f->a[i] != 99 || p.m.s2->f->c[i] != 99)
+      abort ();
+
+  zero_arrays (&p, N);
+
+  for (int i = 0; i < 99; i++)
+    {
+#pragma acc enter data copyin(p.m.s2[:1]) copyin(p.n.s2[:1])
+#pragma acc enter data copyin(p.m.s2->f[:1]) copyin(p.n.s2->f[:1])
+#pragma acc parallel loop copy(p.m.s2->f->a[:N]) copy(p.m.s2->f->c[:N]) \
+                         copy(p.n.s2->f->a[:N]) copy(p.n.s2->f->c[:N])
+       for (int j = 0; j < N; j++)
+         {
+           p.m.s2->f->a[j]++;
+           p.m.s2->f->c[j]++;
+           p.n.s2->f->a[j]++;
+           p.n.s2->f->c[j]++;
+         }
+#pragma acc exit data delete(p.m.s2->f[:1]) delete(p.n.s2->f[:1])
+#pragma acc exit data delete(p.m.s2[:1]) delete(p.n.s2[:1])
+    }
+
+  for (i = 0; i < N; i++)
+    if (p.m.s2->f->a[i] != 99 || p.m.s2->f->c[i] != 99
+       || p.n.s2->f->a[i] != 99 || p.n.s2->f->c[i] != 99)
+      abort ();
+
+  zero_arrays (&p, N);
+
+  for (int i = 0; i < 99; i++)
+    {
+#pragma acc enter data copyin(p.m.s2[:1]) copyin(p.n.s2[:1])
+#pragma acc enter data copyin(p.n.s2->e[:N]) copyin(p.n.s2->f[:1]) \
+                      copyin(p.m.s2->f[:1])
+#pragma acc parallel loop copy(p.m.s2->f->a[:N]) copy(p.n.s2->f->a[:N])
+       for (int j = 0; j < N; j++)
+         {
+           p.m.s2->f->a[j]++;
+           p.n.s2->f->a[j]++;
+           p.n.s2->e[j]++;
+         }
+#pragma acc exit data delete(p.m.s2->f[:1]) delete(p.n.s2->f[:1]) \
+                     copyout(p.n.s2->e[:N])
+#pragma acc exit data delete(p.m.s2[:1]) delete(p.n.s2[:1])
+    }
+
+  for (i = 0; i < N; i++)
+    if (p.m.s2->f->a[i] != 99 || p.n.s2->f->a[i] != 99
+       || p.n.s2->e[i] != 99)
+      abort ();
+
+  zero_arrays (q, N);
+
+  for (int i = 0; i < 99; i++)
+    {
+#pragma acc enter data copyin(q->m.s2[:1])
+#pragma acc parallel loop copy(q->m.s2->e[:N])
+      for (int j = 0; j < N; j++)
+       q->m.s2->e[j]++;
+#pragma acc exit data delete(q->m.s2[:1])
+    }
+
+  for (i = 0; i < N; i++)
+    if (q->m.s2->e[i] != 99)
+      abort ();
+
+  zero_arrays (q, N);
+
+  for (int i = 0; i < 99; i++)
+    {
+#pragma acc enter data copyin(q->m.s2[:1])
+#pragma acc enter data copyin(q->m.s2->f[:1])
+#pragma acc parallel loop copy(q->m.s2->f->a[:N]) copy(q->m.s2->f->c[:N])
+       for (int j = 0; j < N; j++)
+         {
+           q->m.s2->f->a[j]++;
+           q->m.s2->f->c[j]++;
+         }
+#pragma acc exit data delete(q->m.s2->f[:1])
+#pragma acc exit data delete(q->m.s2[:1])
+    }
+
+  for (i = 0; i < N; i++)
+    if (q->m.s2->f->a[i] != 99 || q->m.s2->f->c[i] != 99)
+      abort ();
+
+  zero_arrays (q, N);
+
+  for (int i = 0; i < 99; i++)
+    {
+#pragma acc enter data copyin(q->m.s2[:1]) copyin(q->n.s2[:1])
+#pragma acc enter data copyin(q->m.s2->f[:1]) copyin(q->n.s2->f[:1])
+#pragma acc parallel loop copy(q->m.s2->f->a[:N]) copy(q->m.s2->f->c[:N]) \
+                         copy(q->n.s2->f->a[:N]) copy(q->n.s2->f->c[:N])
+       for (int j = 0; j < N; j++)
+         {
+           q->m.s2->f->a[j]++;
+           q->m.s2->f->c[j]++;
+           q->n.s2->f->a[j]++;
+           q->n.s2->f->c[j]++;
+         }
+#pragma acc exit data delete(q->m.s2->f[:1]) delete(q->n.s2->f[:1])
+#pragma acc exit data delete(q->m.s2[:1]) delete(q->n.s2[:1])
+    }
+
+  for (i = 0; i < N; i++)
+    if (q->m.s2->f->a[i] != 99 || q->m.s2->f->c[i] != 99
+       || q->n.s2->f->a[i] != 99 || q->n.s2->f->c[i] != 99)
+      abort ();
+
+  zero_arrays (q, N);
+
+  for (int i = 0; i < 99; i++)
+    {
+#pragma acc enter data copyin(q->m.s2[:1]) copyin(q->n.s2[:1])
+#pragma acc enter data copyin(q->n.s2->e[:N]) copyin(q->m.s2->f[:1]) \
+                      copyin(q->n.s2->f[:1])
+#pragma acc parallel loop copy(q->m.s2->f->a[:N]) copy(q->n.s2->f->a[:N])
+       for (int j = 0; j < N; j++)
+         {
+           q->m.s2->f->a[j]++;
+           q->n.s2->f->a[j]++;
+           q->n.s2->e[j]++;
+         }
+#pragma acc exit data delete(q->m.s2->f[:1]) delete(q->n.s2->f[:1]) \
+                     copyout(q->n.s2->e[:N])
+#pragma acc exit data delete(q->m.s2[:1]) delete(q->n.s2[:1])
+    }
+
+  for (i = 0; i < N; i++)
+    if (q->m.s2->f->a[i] != 99 || q->n.s2->f->a[i] != 99
+       || q->n.s2->e[i] != 99)
+      abort ();
+
+  return 0;
+}