]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
openmp: Add support for non-VLA {,first}private allocate on omp task
authorJakub Jelinek <jakub@redhat.com>
Sat, 14 Nov 2020 00:46:16 +0000 (01:46 +0100)
committerJakub Jelinek <jakub@redhat.com>
Sat, 14 Nov 2020 00:46:16 +0000 (01:46 +0100)
This patch adds support for custom allocators on private/firstprivate
clauses for task (and taskloop) constructs.  Private didn't need anything
special, but firstprivate if it is passed by reference needs the GOMP_alloc
calls in the copyfn and GOMP_free in the task body.

2020-11-14  Jakub Jelinek  <jakub@redhat.com>

* gimplify.c (gimplify_omp_for): Add OMP_CLAUSE_ALLOCATE_ALLOCATOR
decls as firstprivate on task clauses even when allocate clause
decl is not lastprivate.
* omp-low.c (install_var_field): Don't dereference omp_is_reference
types if mask is 33 rather than 1.
(scan_sharing_clauses): Populate allocate_map even for task
constructs.  For now remove it back for variables mentioned in
reduction and in_reduction clauses on task/taskloop constructs
or on VLA task firstprivates.  For firstprivate on task construct,
install the var field into field_map with by_ref and 33 instead
of false and 1 if mentioned in allocate clause.
(lower_private_allocate): Set TREE_THIS_NOTRAP on the created
MEM_REF.
(lower_rec_input_clauses): Handle allocate for task firstprivatized
non-VLA variables.
(create_task_copyfn): Likewise.

* testsuite/libgomp.c-c++-common/allocate-1.c (struct S): New type.
(foo): Add tests for non-VLA private and firstprivate clauses on
omp task.
(bar): Likewise.  Remove taking of address from private/firstprivate
variables.
* testsuite/libgomp.c++/allocate-1.C (struct S): New type.
(foo): Add p, q, px and s arguments.  Add tests for array reductions
and for non-VLA private and firstprivate clauses on omp task.
(bar): Removed.
(main): Adjust foo caller.  Don't call bar.

gcc/gimplify.c
gcc/omp-low.c
libgomp/testsuite/libgomp.c++/allocate-1.C
libgomp/testsuite/libgomp.c-c++-common/allocate-1.c

index b861e17d8aead9dce8f782b93383c0cb6932b224..2566ec7f0af8dc844901ad0bda2a73fdb4383b4d 100644 (file)
@@ -12463,22 +12463,22 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
          /* Allocate clause we duplicate on task and inner taskloop
             if the decl is lastprivate, otherwise just put on task.  */
          case OMP_CLAUSE_ALLOCATE:
+           if (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c)
+               && DECL_P (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c)))
+             {
+               /* Additionally, put firstprivate clause on task
+                  for the allocator if it is not constant.  */
+               *gtask_clauses_ptr
+                 = build_omp_clause (OMP_CLAUSE_LOCATION (c),
+                                     OMP_CLAUSE_FIRSTPRIVATE);
+               OMP_CLAUSE_DECL (*gtask_clauses_ptr)
+                 = OMP_CLAUSE_ALLOCATE_ALLOCATOR (c);
+               gtask_clauses_ptr = &OMP_CLAUSE_CHAIN (*gtask_clauses_ptr);
+             }
            if (lastprivate_uids
                && bitmap_bit_p (lastprivate_uids,
                                 DECL_UID (OMP_CLAUSE_DECL (c))))
              {
-               if (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c)
-                   && DECL_P (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c)))
-                 {
-                   /* Additionally, put firstprivate clause on task
-                      for the allocator if it is not constant.  */
-                   *gtask_clauses_ptr
-                     = build_omp_clause (OMP_CLAUSE_LOCATION (c),
-                                         OMP_CLAUSE_FIRSTPRIVATE);
-                   OMP_CLAUSE_DECL (*gtask_clauses_ptr)
-                     = OMP_CLAUSE_ALLOCATE_ALLOCATOR (c);
-                   gtask_clauses_ptr = &OMP_CLAUSE_CHAIN (*gtask_clauses_ptr);
-                 }
                *gfor_clauses_ptr = c;
                gfor_clauses_ptr = &OMP_CLAUSE_CHAIN (c);
                *gtask_clauses_ptr = copy_node (c);
index a1604e0ee3c41c050aae3c34fd02d351f7c6690c..09a8cbdc433ab9ec6be9dc2d728470cf941c9ba0 100644 (file)
@@ -803,7 +803,7 @@ install_var_field (tree var, bool by_ref, int mask, omp_context *ctx)
     }
   else if (by_ref)
     type = build_pointer_type (type);
-  else if ((mask & 3) == 1 && omp_is_reference (var))
+  else if ((mask & (32 | 3)) == 1 && omp_is_reference (var))
     type = TREE_TYPE (type);
 
   field = build_decl (DECL_SOURCE_LOCATION (var),
@@ -1141,8 +1141,6 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
            /* omp_default_mem_alloc is 1 */
            || !integer_onep (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c))))
       {
-       if (is_task_ctx (ctx))
-         continue; /* For now.  */
        if (ctx->allocate_map == NULL)
          ctx->allocate_map = new hash_map<tree, tree>;
        ctx->allocate_map->put (OMP_CLAUSE_DECL (c),
@@ -1222,18 +1220,20 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
              ctx->local_reduction_clauses
                = tree_cons (NULL, c, ctx->local_reduction_clauses);
            }
-         if ((OMP_CLAUSE_REDUCTION_INSCAN (c)
-              || OMP_CLAUSE_REDUCTION_TASK (c)) && ctx->allocate_map)
+         /* FALLTHRU */
+
+       case OMP_CLAUSE_IN_REDUCTION:
+         decl = OMP_CLAUSE_DECL (c);
+         if (ctx->allocate_map
+             && ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
+                  && (OMP_CLAUSE_REDUCTION_INSCAN (c)
+                      || OMP_CLAUSE_REDUCTION_TASK (c)))
+                 || is_task_ctx (ctx)))
            {
-             tree decl = OMP_CLAUSE_DECL (c);
              /* For now.  */
              if (ctx->allocate_map->get (decl))
                ctx->allocate_map->remove (decl);
            }
-         /* FALLTHRU */
-
-       case OMP_CLAUSE_IN_REDUCTION:
-         decl = OMP_CLAUSE_DECL (c);
          if (TREE_CODE (decl) == MEM_REF)
            {
              tree t = TREE_OPERAND (decl, 0);
@@ -1317,7 +1317,16 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
          if (is_variable_sized (decl))
            {
              if (is_task_ctx (ctx))
-               install_var_field (decl, false, 1, ctx);
+               {
+                 if (ctx->allocate_map
+                     && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE)
+                   {
+                     /* For now.  */
+                     if (ctx->allocate_map->get (decl))
+                       ctx->allocate_map->remove (decl);
+                   }
+                 install_var_field (decl, false, 1, ctx);
+               }
              break;
            }
          else if (is_taskreg_ctx (ctx))
@@ -1329,7 +1338,11 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
              if (is_task_ctx (ctx)
                  && (global || by_ref || omp_is_reference (decl)))
                {
-                 install_var_field (decl, false, 1, ctx);
+                 if (ctx->allocate_map
+                     && ctx->allocate_map->get (decl))
+                   install_var_field (decl, by_ref, 32 | 1, ctx);
+                 else
+                   install_var_field (decl, false, 1, ctx);
                  if (!global)
                    install_var_field (decl, by_ref, 2, ctx);
                }
@@ -4498,7 +4511,9 @@ lower_private_allocate (tree var, tree new_var, tree &allocator,
   gimple_seq_add_stmt (ilist, g);
   if (!is_ref)
     {
-      SET_DECL_VALUE_EXPR (new_var, build_simple_mem_ref (allocate_ptr));
+      tree x = build_simple_mem_ref (allocate_ptr);
+      TREE_THIS_NOTRAP (x) = 1;
+      SET_DECL_VALUE_EXPR (new_var, x);
       DECL_HAS_VALUE_EXPR_P (new_var) = 1;
     }
   return true;
@@ -5409,7 +5424,18 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
              if (c_kind == OMP_CLAUSE_FIRSTPRIVATE && is_task_ctx (ctx))
                {
                  x = build_receiver_ref (var, false, ctx);
-                 x = build_fold_addr_expr_loc (clause_loc, x);
+                 if (ctx->allocate_map)
+                   if (tree *allocatep = ctx->allocate_map->get (var))
+                     {
+                       allocator = *allocatep;
+                       if (TREE_CODE (allocator) != INTEGER_CST)
+                         allocator = build_outer_var_ref (allocator, ctx);
+                       allocator = fold_convert (pointer_sized_int_node,
+                                                 allocator);
+                       allocate_ptr = unshare_expr (x);
+                     }
+                 if (allocator == NULL_TREE)
+                   x = build_fold_addr_expr_loc (clause_loc, x);
                }
              else if (lower_private_allocate (var, new_var, allocator,
                                               allocate_ptr,
@@ -5676,6 +5702,18 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
                gimplify_and_add (x, dlist);
              if (allocator)
                {
+                 if (!is_gimple_val (allocator))
+                   {
+                     tree avar = create_tmp_var (TREE_TYPE (allocator));
+                     gimplify_assign (avar, allocator, dlist);
+                     allocator = avar;
+                   }
+                 if (!is_gimple_val (allocate_ptr))
+                   {
+                     tree apvar = create_tmp_var (TREE_TYPE (allocate_ptr));
+                     gimplify_assign (apvar, allocate_ptr, dlist);
+                     allocate_ptr = apvar;
+                   }
                  tree f = builtin_decl_explicit (BUILT_IN_GOMP_FREE);
                  gimple *g
                    = gimple_build_call (f, 2, allocate_ptr, allocator);
@@ -5704,6 +5742,18 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
                           || use_pointer_for_field (var, NULL))
                    {
                      x = build_receiver_ref (var, false, ctx);
+                     if (ctx->allocate_map)
+                       if (tree *allocatep = ctx->allocate_map->get (var))
+                         {
+                           allocator = *allocatep;
+                           if (TREE_CODE (allocator) != INTEGER_CST)
+                             allocator = build_outer_var_ref (allocator, ctx);
+                           allocator = fold_convert (pointer_sized_int_node,
+                                                     allocator);
+                           allocate_ptr = unshare_expr (x);
+                           x = build_simple_mem_ref (x);
+                           TREE_THIS_NOTRAP (x) = 1;
+                         }
                      SET_DECL_VALUE_EXPR (new_var, x);
                      DECL_HAS_VALUE_EXPR_P (new_var) = 1;
                      goto do_dtor;
@@ -11290,7 +11340,35 @@ create_task_copyfn (gomp_task *task_stmt, omp_context *ctx)
        if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_FIRSTPRIVATE)
          t = build2 (MODIFY_EXPR, TREE_TYPE (dst), dst, src);
        else
-         t = lang_hooks.decls.omp_clause_copy_ctor (c, dst, src);
+         {
+           if (ctx->allocate_map)
+             if (tree *allocatorp = ctx->allocate_map->get (decl))
+               {
+                 tree allocator = *allocatorp;
+                 if (TREE_CODE (allocator) != INTEGER_CST)
+                   {
+                     n = splay_tree_lookup (ctx->sfield_map,
+                                            (splay_tree_key) allocator);
+                     allocator = (tree) n->value;
+                     if (tcctx.cb.decl_map)
+                       allocator = *tcctx.cb.decl_map->get (allocator);
+                     tree a = build_simple_mem_ref_loc (loc, sarg);
+                     allocator = omp_build_component_ref (a, allocator);
+                   }
+                 allocator = fold_convert (pointer_sized_int_node, allocator);
+                 tree a = builtin_decl_explicit (BUILT_IN_GOMP_ALLOC);
+                 tree align = build_int_cst (size_type_node,
+                                             DECL_ALIGN_UNIT (decl));
+                 tree sz = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (dst)));
+                 tree ptr = build_call_expr_loc (loc, a, 3, align, sz,
+                                                 allocator);
+                 ptr = fold_convert (TREE_TYPE (dst), ptr);
+                 t = build2 (MODIFY_EXPR, TREE_TYPE (dst), dst, ptr);
+                 append_to_statement_list (t, &list);
+                 dst = build_simple_mem_ref_loc (loc, dst);
+               }
+           t = lang_hooks.decls.omp_clause_copy_ctor (c, dst, src);
+         }
        append_to_statement_list (t, &list);
        break;
       case OMP_CLAUSE_PRIVATE:
index ee89f31b6b3563a9be3ac076a3763e070505aeb2..0876719f0a1c248be85c14f5e8af9cd44e1311cd 100644 (file)
@@ -2,17 +2,26 @@
 #include <stdlib.h>
 #include <stdint.h>
 
+struct S { int a, b; };
+
 void
-foo (int &x, int &y, int &r, int &l, int (&l2)[4], int &l3, int &n, omp_allocator_handle_t h, int fl)
+foo (int &x, int &y, int &r, int &l, int (&l2)[4], int &l3, int &n, int *&p,
+     int *&q, int &px, struct S &s, omp_allocator_handle_t h, int fl)
 {
   int i;
   typedef int T[x];
   T v, w;
   T &v2 = v;
   T &w2 = w;
+  int r1[4] = { 0, 0, 0, 0 };
+  int (&r2)[4] = r1;
   int xo = x;
   for (i = 0; i < x; i++)
     w[i] = i;
+  for (i = 0; i < 4; i++)
+    p[i] = 0;
+  for (i = 0; i < 3; i++)
+    q[i] = 0;
   #pragma omp parallel private (y, v2) firstprivate (x) allocate (x, y, v2)
   {
     int *volatile p1 = &x;
@@ -66,6 +75,7 @@ foo (int &x, int &y, int &r, int &l, int (&l2)[4], int &l3, int &n, omp_allocato
                        | (uintptr_t) &l | (uintptr_t) &n) & 63) != 0)
        abort ();
     }
+  x = xo;
   #pragma omp parallel
   {
     #pragma omp for lastprivate (l2) allocate (h: l2, l3) lastprivate (conditional: l3)
@@ -80,84 +90,86 @@ foo (int &x, int &y, int &r, int &l, int (&l2)[4], int &l3, int &n, omp_allocato
        if ((fl & 1) && (((uintptr_t) &l2[0] | (uintptr_t) &l3) & 63) != 0)
          abort ();
       }
-  }
-  if (r != 64 * 63 / 2 || l != 63 || n != 8 + 16 * 64)
-    abort ();
-  if (l2[0] != 63 || l2[1] != 63 + 1 || l2[2] != 63 + 2 || l2[3] != 63 + 3 || l3 != 36)
-    abort ();
-}
-
-void
-bar (int &x, int &y, int &r, int &l, int (&l2)[4], int &l3, int &n, omp_allocator_handle_t h)
-{
-  int i;
-  typedef int T[x];
-  T v, w;
-  T &v2 = v;
-  T &w2 = w;
-  int xo = x;
-  for (i = 0; i < x; i++)
-    w[i] = i;
-  #pragma omp parallel private (y, v2) firstprivate (x) allocate (x, y, v2)
-  {
-    int *volatile p1 = &x;
-    int *volatile p2 = &y;
-    if (x != 42)
-      abort ();
-    #pragma omp barrier
-    *p2 = 1;
-    p1[0]++;
-    v2[0] = 7;
-    v2[41] = 8;
-    #pragma omp barrier
-    if (x != 43 || y != 1)
-      abort ();
-    if (v2[0] != 7 || v2[41] != 8)
-      abort ();
-  }
-  x = xo;
-  #pragma omp teams
-  #pragma omp parallel private (y) firstprivate (x, w2) allocate (h: x, y, w2)
-  {
-    int *volatile p1 = &x;
-    int *volatile p2 = &y;
-    if (x != 42 || w2[17] != 17 || w2[41] != 41)
-      abort ();
-    #pragma omp barrier
-    *p2 = 1;
-    p1[0]++;
-    #pragma omp barrier
-    if (x != 43 || y != 1)
-      abort ();
-  }
-  x = xo;
-  #pragma omp parallel for private (y) firstprivate (x) allocate (h: x, y, r, l, n) reduction(+: r) lastprivate (l) linear (n: 16)
-  for (i = 0; i < 64; i++)
+    #pragma omp for reduction(+:p[2:px], q[:3], r2) allocate(h: p, q, r2)
+    for (i = 0; i < 32; i++)
+      {
+       p[2] += i;
+       p[3] += 2 * i;
+       q[0] += 3 * i;
+       q[2] += 4 * i;
+       r2[0] += 5 * i;
+       r2[3] += 6 * i;
+       /* Can't really rely on alignment of &p[0], the implementation could
+          allocate the whole array or do what GCC does and allocate only part
+          of it.  */
+       if ((fl & 1) && (((uintptr_t) &q[0] | (uintptr_t) &r2[0]) & 63) != 0)
+         abort ();
+      }
+    #pragma omp task private(y) firstprivate(x) allocate(x, y)
     {
+      int *volatile p1 = &x;
+      int *volatile p2 = &y;
       if (x != 42)
        abort ();
-      y = 1;
-      l = i;
-      n += y + 15;
-      r += i;
+      p1[0]++;
+      p2[0] = 21;
+      if (x != 43 || y != 21)
+       abort ();
+      if ((fl & 2) && (((uintptr_t) p1 | (uintptr_t) p2) & 63) != 0)
+       abort ();
+    }
+    #pragma omp task private(y) firstprivate(x) allocate(h: x, y)
+    {
+      int *volatile p1 = &x;
+      int *volatile p2 = &y;
+      if (x != 42)
+       abort ();
+      p1[0]++;
+      p2[0] = 21;
+      if (x != 43 || y != 21)
+       abort ();
+      if ((fl & 1) && (((uintptr_t) p1 | (uintptr_t) p2) & 63) != 0)
+       abort ();
+    }
+    #pragma omp task private(y) firstprivate(s) allocate(s, y)
+    {
+      int *volatile p1 = &s.a;
+      int *volatile p2 = &s.b;
+      int *volatile p3 = &y;
+      if (s.a != 27 || s.b != 29)
+       abort ();
+      p1[0]++;
+      p2[0]++;
+      p3[0] = 21;
+      if (s.a != 28 || s.b != 30 || y != 21)
+       abort ();
+      if ((fl & 2) && (((uintptr_t) p1 | (uintptr_t) p3) & 63) != 0)
+       abort ();
+    }
+    #pragma omp task private(y) firstprivate(s) allocate(h: s, y)
+    {
+      int *volatile p1 = &s.a;
+      int *volatile p2 = &s.b;
+      int *volatile p3 = &y;
+      if (s.a != 27 || s.b != 29)
+       abort ();
+      p1[0]++;
+      p2[0]++;
+      p3[0] = 21;
+      if (s.a != 28 || s.b != 30 || y != 21)
+       abort ();
+      if ((fl & 1) && (((uintptr_t) p1 | (uintptr_t) p3) & 63) != 0)
+       abort ();
     }
-  #pragma omp parallel
-  {
-    #pragma omp for lastprivate (l2) allocate (h: l2, l3) lastprivate (conditional: l3)
-    for (i = 0; i < 64; i++)
-      {
-       l2[0] = i;
-       l2[1] = i + 1;
-       l2[2] = i + 2;
-       l2[3] = i + 3;
-       if (i < 37)
-         l3 = i;
-      }
   }
   if (r != 64 * 63 / 2 || l != 63 || n != 8 + 16 * 64)
     abort ();
   if (l2[0] != 63 || l2[1] != 63 + 1 || l2[2] != 63 + 2 || l2[3] != 63 + 3 || l3 != 36)
     abort ();
+  if (p[2] != (32 * 31) / 2 || p[3] != 2 * (32 * 31) / 2
+      || q[0] != 3 * (32 * 31) / 2 || q[2] != 4 * (32 * 31) / 2
+      || r2[0] != 5 * (32 * 31) / 2 || r2[3] != 6 * (32 * 31) / 2)
+    abort ();
 }
 
 int
@@ -171,24 +183,25 @@ main ()
   if (a == omp_null_allocator)
     abort ();
   omp_set_default_allocator (omp_default_mem_alloc);
+  struct S s = { 27, 29 };
+  int p1[4], q1[3], px = 2;
+  int *p = p1;
+  int *q = q1;
   int x = 42, y = 0, r = 0, l, l2[4], l3, n = 8;
-  foo (x, y, r, l, l2, l3, n, omp_null_allocator, 0);
+  foo (x, y, r, l, l2, l3, n, p, q, px, s, omp_null_allocator, 0);
   x = 42; y = 0; r = 0; l = -1; l2[0] = -1; l2[1] = -1;
   l2[2] = -1; l2[3] = -1; n = 8;
-  foo (x, y, r, l, l2, l3, n, omp_default_mem_alloc, 0);
+  foo (x, y, r, l, l2, l3, n, p, q, px, s, omp_default_mem_alloc, 0);
   x = 42; y = 0; r = 0; l = -1; l2[0] = -1; l2[1] = -1;
   l2[2] = -1; l2[3] = -1; n = 8;
-  foo (x, y, r, l, l2, l3, n, a, 1);
+  foo (x, y, r, l, l2, l3, n, p, q, px, s, a, 1);
   x = 42; y = 0; r = 0; l = -1; l2[0] = -1; l2[1] = -1;
   l2[2] = -1; l2[3] = -1; n = 8;
   omp_set_default_allocator (a);
-  foo (x, y, r, l, l2, l3, n, omp_null_allocator, 3);
-  x = 42; y = 0; r = 0; l = -1; l2[0] = -1; l2[1] = -1;
-  l2[2] = -1; l2[3] = -1; n = 8;
-  foo (x, y, r, l, l2, l3, n, omp_default_mem_alloc, 2);
+  foo (x, y, r, l, l2, l3, n, p, q, px, s, omp_null_allocator, 3);
   x = 42; y = 0; r = 0; l = -1; l2[0] = -1; l2[1] = -1;
   l2[2] = -1; l2[3] = -1; n = 8;
-  bar (x, y, r, l, l2, l3, n, a);
+  foo (x, y, r, l, l2, l3, n, p, q, px, s, omp_default_mem_alloc, 2);
   omp_destroy_allocator (a);
   return 0;
 }
index 5dd51b5a2b96504560b9e111af5ec092e8d2137a..4398ff957ef0e805d2af307f4255ceae01849018 100644 (file)
@@ -2,6 +2,8 @@
 #include <stdlib.h>
 #include <stdint.h>
 
+struct S { int a, b; };
+
 void
 foo (int x, int *p, int *q, int px, omp_allocator_handle_t h, int fl)
 {
@@ -13,6 +15,7 @@ foo (int x, int *p, int *q, int px, omp_allocator_handle_t h, int fl)
   int v[x], w[x];
   int r2[4] = { 0, 0, 0, 0 };
   int xo = x;
+  struct S s = { 27, 29 };
   for (i = 0; i < 4; i++)
     p[i] = 0;
   for (i = 0; i < 3; i++)
@@ -72,6 +75,7 @@ foo (int x, int *p, int *q, int px, omp_allocator_handle_t h, int fl)
                        | (uintptr_t) &l | (uintptr_t) &n) & 63) != 0)
        abort ();
     }
+  x = xo;
   #pragma omp parallel
   {
     #pragma omp for lastprivate (l2) private (i1) allocate (h: l2, l3, i1) lastprivate (conditional: l3)
@@ -137,6 +141,62 @@ foo (int x, int *p, int *q, int px, omp_allocator_handle_t h, int fl)
        if ((fl & 1) && (((uintptr_t) &q[0] | (uintptr_t) &r2[0]) & 63) != 0)
          abort ();
       }
+    #pragma omp task private(y) firstprivate(x) allocate(x, y)
+    {
+      int *volatile p1 = &x;
+      int *volatile p2 = &y;
+      if (x != 42)
+       abort ();
+      p1[0]++;
+      p2[0] = 21;
+      if (x != 43 || y != 21)
+       abort ();
+      if ((fl & 2) && (((uintptr_t) p1 | (uintptr_t) p2) & 63) != 0)
+       abort ();
+    }
+    #pragma omp task private(y) firstprivate(x) allocate(h: x, y)
+    {
+      int *volatile p1 = &x;
+      int *volatile p2 = &y;
+      if (x != 42)
+       abort ();
+      p1[0]++;
+      p2[0] = 21;
+      if (x != 43 || y != 21)
+       abort ();
+      if ((fl & 1) && (((uintptr_t) p1 | (uintptr_t) p2) & 63) != 0)
+       abort ();
+    }
+    #pragma omp task private(y) firstprivate(s) allocate(s, y)
+    {
+      int *volatile p1 = &s.a;
+      int *volatile p2 = &s.b;
+      int *volatile p3 = &y;
+      if (s.a != 27 || s.b != 29)
+       abort ();
+      p1[0]++;
+      p2[0]++;
+      p3[0] = 21;
+      if (s.a != 28 || s.b != 30 || y != 21)
+       abort ();
+      if ((fl & 2) && (((uintptr_t) p1 | (uintptr_t) p3) & 63) != 0)
+       abort ();
+    }
+    #pragma omp task private(y) firstprivate(s) allocate(h: s, y)
+    {
+      int *volatile p1 = &s.a;
+      int *volatile p2 = &s.b;
+      int *volatile p3 = &y;
+      if (s.a != 27 || s.b != 29)
+       abort ();
+      p1[0]++;
+      p2[0]++;
+      p3[0] = 21;
+      if (s.a != 28 || s.b != 30 || y != 21)
+       abort ();
+      if ((fl & 1) && (((uintptr_t) p1 | (uintptr_t) p3) & 63) != 0)
+       abort ();
+    }
   }
   if (r != 64 * 63 / 2 || l != 63 || n != 8 + 16 * 64)
     abort ();
@@ -164,16 +224,15 @@ bar (int x, omp_allocator_handle_t h)
   int i3, j3, n3 = 10, l5;
   int i4, j4, n4 = 11, l6;
   int i5;
+  struct S s = { 27, 29 };
   int xo = x;
   #pragma omp parallel private (y) firstprivate (x) allocate (x, y)
   {
-    int *volatile p1 = &x;
-    int *volatile p2 = &y;
     if (x != 42)
       abort ();
     #pragma omp barrier
-    *p2 = 1;
-    p1[0]++;
+    y = 1;
+    x++;
     #pragma omp barrier
     if (x != 43 || y != 1)
       abort ();
@@ -182,13 +241,11 @@ bar (int x, omp_allocator_handle_t h)
   #pragma omp teams
   #pragma omp parallel private (y) firstprivate (x) allocate (h: x, y)
   {
-    int *volatile p1 = &x;
-    int *volatile p2 = &y;
     if (x != 42)
       abort ();
     #pragma omp barrier
-    *p2 = 1;
-    p1[0]++;
+    y = 1;
+    x++;
     #pragma omp barrier
     if (x != 43 || y != 1)
       abort ();
@@ -204,6 +261,7 @@ bar (int x, omp_allocator_handle_t h)
       n += y + 15;
       r += i;
     }
+  x = xo;
   #pragma omp parallel
   {
     #pragma omp for lastprivate (l2) private (i1) allocate (h: l2, l3, i1) lastprivate (conditional: l3)
@@ -240,6 +298,44 @@ bar (int x, omp_allocator_handle_t h)
     #pragma omp for lastprivate (i5) allocate (i5)
     for (i5 = 1; i5 < 17; i5 += 3)
       ;
+    #pragma omp task private(y) firstprivate(x) allocate(x, y)
+    {
+      if (x != 42)
+       abort ();
+      x++;
+      y = 21;
+      if (x != 43 || y != 21)
+       abort ();
+    }
+    #pragma omp task private(y) firstprivate(x) allocate(h: x, y)
+    {
+      if (x != 42)
+       abort ();
+      x++;
+      y = 21;
+      if (x != 43 || y != 21)
+       abort ();
+    }
+    #pragma omp task private(y) firstprivate(s) allocate(s, y)
+    {
+      if (s.a != 27 || s.b != 29)
+       abort ();
+      s.a++;
+      s.b++;
+      y = 21;
+      if (s.a != 28 || s.b != 30 || y != 21)
+       abort ();
+    }
+    #pragma omp task private(y) firstprivate(s) allocate(h: s, y)
+    {
+      if (s.a != 27 || s.b != 29)
+       abort ();
+      s.a++;
+      s.b++;
+      y = 21;
+      if (s.a != 28 || s.b != 30 || y != 21)
+       abort ();
+    }
   }
   if (r != 64 * 63 / 2 || l != 63 || n != 8 + 16 * 64)
     abort ();