]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
openmp: Add support for allocator and align modifiers on allocate clauses
authorJakub Jelinek <jakub@redhat.com>
Wed, 22 Sep 2021 07:52:32 +0000 (09:52 +0200)
committerTobias Burnus <tobias@codesourcery.com>
Wed, 22 Sep 2021 07:57:15 +0000 (09:57 +0200)
As the allocate-2.c testcase shows, this change isn't 100% backwards compatible,
one could have allocate and/or align functions that return an OpenMP allocator
handle and previously it would call those functions and now would use those
names as keywords for the modifiers.  But it allows specify extra alignment
requirements for the allocations.

2021-09-22  Jakub Jelinek  <jakub@redhat.com>

gcc/
* tree.h (OMP_CLAUSE_ALLOCATE_ALIGN): Define.
* tree.c (omp_clause_num_ops): Change number of OMP_CLAUSE_ALLOCATE
arguments from 2 to 3.
* tree-pretty-print.c (dump_omp_clause): Print allocator() around
allocate clause allocator and print align if present.
* omp-low.c (scan_sharing_clauses): Force allocate_map entry even
for omp_default_mem_alloc if align modifier is present.  If align
modifier is present, use TREE_LIST to encode both allocator and
align.
(lower_private_allocate, lower_rec_input_clauses, create_task_copyfn):
Handle align modifier on allocator clause if present.
gcc/c-family/
* c-omp.c (c_omp_split_clauses): Copy over OMP_CLAUSE_ALLOCATE_ALIGN.
gcc/c/
* c-parser.c (c_parser_omp_clause_allocate): Parse allocate clause
modifiers.
gcc/cp/
* parser.c (cp_parser_omp_clause_allocate): Parse allocate clause
modifiers.
* semantics.c (finish_omp_clauses) <OMP_CLAUSE_ALLOCATE>: Perform
semantic analysis of OMP_CLAUSE_ALLOCATE_ALIGN.
* pt.c (tsubst_omp_clauses) <case OMP_CLAUSE_ALLOCATE>: Handle
also OMP_CLAUSE_ALLOCATE_ALIGN.
gcc/testsuite/
* c-c++-common/gomp/allocate-6.c: New test.
* c-c++-common/gomp/allocate-7.c: New test.
* g++.dg/gomp/allocate-4.C: New test.
libgomp/
* testsuite/libgomp.c-c++-common/allocate-2.c: New test.
* testsuite/libgomp.c-c++-common/allocate-3.c: New test.

(cherry picked from commit 059b819e3c94aae3dd0be55bd512ee6ee4e28798)

20 files changed:
gcc/ChangeLog.omp
gcc/c-family/ChangeLog.omp
gcc/c-family/c-omp.c
gcc/c/ChangeLog.omp
gcc/c/c-parser.c
gcc/cp/ChangeLog.omp
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/omp-low.c
gcc/testsuite/ChangeLog.omp
gcc/testsuite/c-c++-common/gomp/allocate-6.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/gomp/allocate-7.c [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/allocate-4.C [new file with mode: 0644]
gcc/tree-pretty-print.c
gcc/tree.c
gcc/tree.h
libgomp/ChangeLog.omp
libgomp/testsuite/libgomp.c-c++-common/allocate-2.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c-c++-common/allocate-3.c [new file with mode: 0644]

index b6fbc1402ca5fd99d055d88b18d490337b876bda..a84e0411304b8951e793fa8e08c67434e59315e7 100644 (file)
@@ -1,3 +1,20 @@
+2021-09-22  Tobias Burnus  <tobias@codesourcery.com>
+
+       Backported from master:
+       2021-09-22  Jakub Jelinek  <jakub@redhat.com>
+
+       * tree.h (OMP_CLAUSE_ALLOCATE_ALIGN): Define.
+       * tree.c (omp_clause_num_ops): Change number of OMP_CLAUSE_ALLOCATE
+       arguments from 2 to 3.
+       * tree-pretty-print.c (dump_omp_clause): Print allocator() around
+       allocate clause allocator and print align if present.
+       * omp-low.c (scan_sharing_clauses): Force allocate_map entry even
+       for omp_default_mem_alloc if align modifier is present.  If align
+       modifier is present, use TREE_LIST to encode both allocator and
+       align.
+       (lower_private_allocate, lower_rec_input_clauses, create_task_copyfn):
+       Handle align modifier on allocator clause if present.
+
 2021-09-20  Tobias Burnus  <tobias@codesourcery.com>
 
        Backported from master:
index 85dcf77711f8489b506bc6027d915a1ad3494ded..7a8616e7ee6a48d8f453c95a5041d78c58db1307 100644 (file)
@@ -1,3 +1,10 @@
+2021-09-22  Tobias Burnus  <tobias@codesourcery.com>
+
+       Backported from master:
+       2021-09-22  Jakub Jelinek  <jakub@redhat.com>
+
+       * c-omp.c (c_omp_split_clauses): Copy over OMP_CLAUSE_ALLOCATE_ALIGN.
+
 2021-09-20  Tobias Burnus  <tobias@codesourcery.com>
 
        Backported from master:
index d224b2268717ce558b06d44457e85f82f5e31798..5669718a0bd340319622acb0cceaf6152fbe55b7 100644 (file)
@@ -2656,6 +2656,8 @@ c_omp_split_clauses (location_t loc, enum tree_code code,
                    = OMP_CLAUSE_DECL (clauses);
                  OMP_CLAUSE_ALLOCATE_ALLOCATOR (c)
                    = OMP_CLAUSE_ALLOCATE_ALLOCATOR (clauses);
+                 OMP_CLAUSE_ALLOCATE_ALIGN (c)
+                   = OMP_CLAUSE_ALLOCATE_ALIGN (clauses);
                  OMP_CLAUSE_CHAIN (c) = cclauses[s];
                  cclauses[s] = c;
                  has_dup_allocate = true;
index 4a1d1da0b1f32e4a299794e413c91b1403c7d8ea..434d5adeb66149b38dbf87210309510225264ed6 100644 (file)
@@ -1,3 +1,11 @@
+2021-09-22  Tobias Burnus  <tobias@codesourcery.com>
+
+       Backported from master:
+       2021-09-22  Jakub Jelinek  <jakub@redhat.com>
+
+       * c-parser.c (c_parser_omp_clause_allocate): Parse allocate clause
+       modifiers.
+
 2021-09-20  Tobias Burnus  <tobias@codesourcery.com>
 
        Backported from master:
index 1819f6dc64940978e30e5c62ee1da3eb87e4c90c..ebec1305f79bd12c0455bd5c9bc2bdc3d4aacb10 100644 (file)
@@ -15322,7 +15322,15 @@ c_parser_omp_clause_aligned (c_parser *parser, tree list)
 
 /* OpenMP 5.0:
    allocate ( variable-list )
-   allocate ( expression : variable-list ) */
+   allocate ( expression : variable-list )
+
+   OpenMP 5.1:
+   allocate ( allocator-modifier : variable-list )
+   allocate ( allocator-modifier , allocator-modifier : variable-list )
+
+   allocator-modifier:
+   allocator ( expression )
+   align ( expression )  */
 
 static tree
 c_parser_omp_clause_allocate (c_parser *parser, tree list)
@@ -15330,6 +15338,7 @@ c_parser_omp_clause_allocate (c_parser *parser, tree list)
   location_t clause_loc = c_parser_peek_token (parser)->location;
   tree nl, c;
   tree allocator = NULL_TREE;
+  tree align = NULL_TREE;
 
   matching_parens parens;
   if (!parens.require_open (parser))
@@ -15340,17 +15349,128 @@ c_parser_omp_clause_allocate (c_parser *parser, tree list)
       || (c_parser_peek_2nd_token (parser)->type != CPP_COMMA
          && c_parser_peek_2nd_token (parser)->type != CPP_CLOSE_PAREN))
     {
-      location_t expr_loc = c_parser_peek_token (parser)->location;
-      c_expr expr = c_parser_expr_no_commas (parser, NULL);
-      expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
-      allocator = expr.value;
-      allocator = c_fully_fold (allocator, false, NULL);
-      tree orig_type
-       = expr.original_type ? expr.original_type : TREE_TYPE (allocator);
-      orig_type = TYPE_MAIN_VARIANT (orig_type);
-      if (!INTEGRAL_TYPE_P (TREE_TYPE (allocator))
-         || TREE_CODE (orig_type) != ENUMERAL_TYPE
-         || TYPE_NAME (orig_type) != get_identifier ("omp_allocator_handle_t"))
+      bool has_modifiers = false;
+      tree orig_type = NULL_TREE;
+      if (c_parser_next_token_is (parser, CPP_NAME)
+         && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN)
+       {
+         unsigned int n = 3;
+         const char *p
+           = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+         if ((strcmp (p, "allocator") == 0 || strcmp (p, "align") == 0)
+             && c_parser_check_balanced_raw_token_sequence (parser, &n)
+             && (c_parser_peek_nth_token_raw (parser, n)->type
+                 == CPP_CLOSE_PAREN))
+           {
+             if (c_parser_peek_nth_token_raw (parser, n + 1)->type
+                 == CPP_COLON)
+               has_modifiers = true;
+             else if (c_parser_peek_nth_token_raw (parser, n + 1)->type
+                      == CPP_COMMA
+                      && (c_parser_peek_nth_token_raw (parser, n + 2)->type
+                          == CPP_NAME)
+                      && (c_parser_peek_nth_token_raw (parser, n + 3)->type
+                          == CPP_OPEN_PAREN))
+               {
+                 c_token *tok = c_parser_peek_nth_token_raw (parser, n + 2);
+                 const char *q = IDENTIFIER_POINTER (tok->value);
+                 n += 4;
+                 if ((strcmp (q, "allocator") == 0
+                      || strcmp (q, "align") == 0)
+                     && c_parser_check_balanced_raw_token_sequence (parser,
+                                                                    &n)
+                     && (c_parser_peek_nth_token_raw (parser, n)->type
+                         == CPP_CLOSE_PAREN)
+                     && (c_parser_peek_nth_token_raw (parser, n + 1)->type
+                         == CPP_COLON))
+                   has_modifiers = true;
+               }
+           }
+         if (has_modifiers)
+           {
+             c_parser_consume_token (parser);
+             matching_parens parens2;;
+             parens2.require_open (parser);
+             location_t expr_loc = c_parser_peek_token (parser)->location;
+             c_expr expr = c_parser_expr_no_commas (parser, NULL);
+             expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
+             if (strcmp (p, "allocator") == 0)
+               {
+                 allocator = expr.value;
+                 allocator = c_fully_fold (allocator, false, NULL);
+                 orig_type = expr.original_type
+                             ? expr.original_type : TREE_TYPE (allocator);
+                 orig_type = TYPE_MAIN_VARIANT (orig_type);
+               }
+             else
+               {
+                 align = expr.value;
+                 align = c_fully_fold (align, false, NULL);
+               }
+             parens2.skip_until_found_close (parser);
+             if (c_parser_next_token_is (parser, CPP_COMMA))
+               {
+                 c_parser_consume_token (parser);
+                 c_token *tok = c_parser_peek_token (parser);
+                 const char *q = "";
+                 if (c_parser_next_token_is (parser, CPP_NAME))
+                   q = IDENTIFIER_POINTER (tok->value);
+                 if (strcmp (q, "allocator") != 0 && strcmp (q, "align") != 0)
+                   {
+                     c_parser_error (parser, "expected %<allocator%> or "
+                                             "%<align%>");
+                     parens.skip_until_found_close (parser);
+                     return list;
+                   }
+                 else if (strcmp (p, q) == 0)
+                   {
+                     error_at (tok->location, "duplicate %qs modifier", p);
+                     parens.skip_until_found_close (parser);
+                     return list;
+                   }
+                 c_parser_consume_token (parser);
+                 if (!parens2.require_open (parser))
+                   {
+                     parens.skip_until_found_close (parser);
+                     return list;
+                   }
+                 expr_loc = c_parser_peek_token (parser)->location;
+                 expr = c_parser_expr_no_commas (parser, NULL);
+                 expr = convert_lvalue_to_rvalue (expr_loc, expr, false,
+                                                  true);
+                 if (strcmp (q, "allocator") == 0)
+                   {
+                     allocator = expr.value;
+                     allocator = c_fully_fold (allocator, false, NULL);
+                     orig_type = expr.original_type
+                                 ? expr.original_type : TREE_TYPE (allocator);
+                     orig_type = TYPE_MAIN_VARIANT (orig_type);
+                   }
+                 else
+                   {
+                     align = expr.value;
+                     align = c_fully_fold (align, false, NULL);
+                   }
+                 parens2.skip_until_found_close (parser);
+               }
+           }
+       }
+      if (!has_modifiers)
+       {
+         location_t expr_loc = c_parser_peek_token (parser)->location;
+         c_expr expr = c_parser_expr_no_commas (parser, NULL);
+         expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
+         allocator = expr.value;
+         allocator = c_fully_fold (allocator, false, NULL);
+         orig_type = expr.original_type
+                     ? expr.original_type : TREE_TYPE (allocator);
+         orig_type = TYPE_MAIN_VARIANT (orig_type);
+       }
+      if (allocator
+         && (!INTEGRAL_TYPE_P (TREE_TYPE (allocator))
+             || TREE_CODE (orig_type) != ENUMERAL_TYPE
+             || (TYPE_NAME (orig_type)
+                 != get_identifier ("omp_allocator_handle_t"))))
         {
           error_at (clause_loc, "%<allocate%> clause allocator expression "
                                "has type %qT rather than "
@@ -15358,6 +15478,16 @@ c_parser_omp_clause_allocate (c_parser *parser, tree list)
                                TREE_TYPE (allocator));
           allocator = NULL_TREE;
         }
+      if (align
+         && (!INTEGRAL_TYPE_P (TREE_TYPE (align))
+             || !tree_fits_uhwi_p (align)
+             || !integer_pow2p (align)))
+       {
+         error_at (clause_loc, "%<allocate%> clause %<align%> modifier "
+                               "argument needs to be positive constant "
+                               "power of two integer expression");
+         align = NULL_TREE;
+       }
       if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
        {
          parens.skip_until_found_close (parser);
@@ -15368,9 +15498,12 @@ c_parser_omp_clause_allocate (c_parser *parser, tree list)
   nl = c_parser_omp_variable_list (parser, clause_loc,
                                   OMP_CLAUSE_ALLOCATE, list);
 
-  if (allocator)
+  if (allocator || align)
     for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
-      OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) = allocator;
+      {
+       OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) = allocator;
+       OMP_CLAUSE_ALLOCATE_ALIGN (c) = align;
+      }
 
   parens.skip_until_found_close (parser);
   return nl;
index 6cb1f1f18fa86daac9c354a50633ce3134d84720..42fc69c33a79fec57ea077d202ed8f29d468a1ec 100644 (file)
@@ -1,3 +1,15 @@
+2021-09-22  Tobias Burnus  <tobias@codesourcery.com>
+
+       Backported from master:
+       2021-09-22  Jakub Jelinek  <jakub@redhat.com>
+
+       * parser.c (cp_parser_omp_clause_allocate): Parse allocate clause
+       modifiers.
+       * semantics.c (finish_omp_clauses) <OMP_CLAUSE_ALLOCATE>: Perform
+       semantic analysis of OMP_CLAUSE_ALLOCATE_ALIGN.
+       * pt.c (tsubst_omp_clauses) <case OMP_CLAUSE_ALLOCATE>: Handle
+       also OMP_CLAUSE_ALLOCATE_ALIGN.
+
 2021-09-20  Tobias Burnus  <tobias@codesourcery.com>
 
        Backported from master:
index 29bb82e2304f90020eefc8bcdaebc687edc9b437..b6b19deb8b6e4f91895563211d67725ea0459509 100644 (file)
@@ -38088,13 +38088,21 @@ cp_parser_omp_clause_aligned (cp_parser *parser, tree list)
 
 /* OpenMP 5.0:
    allocate ( variable-list )
-   allocate ( expression : variable-list )  */
+   allocate ( expression : variable-list )
+
+   OpenMP 5.1:
+   allocate ( allocator-modifier : variable-list )
+   allocate ( allocator-modifier , allocator-modifier : variable-list )
+
+   allocator-modifier:
+   allocator ( expression )
+   align ( expression )  */
 
 static tree
 cp_parser_omp_clause_allocate (cp_parser *parser, tree list)
 {
-  tree nlist, c, allocator = NULL_TREE;
-  bool colon;
+  tree nlist, c, allocator = NULL_TREE, align = NULL_TREE;
+  bool colon, has_modifiers = false;
 
   matching_parens parens;
   if (!parens.require_open (parser))
@@ -38103,7 +38111,51 @@ cp_parser_omp_clause_allocate (cp_parser *parser, tree list)
   cp_parser_parse_tentatively (parser);
   bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
   parser->colon_corrects_to_scope_p = false;
-  allocator = cp_parser_assignment_expression (parser);
+  for (int mod = 0; mod < 2; mod++)
+    if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)
+       && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_PAREN))
+      {
+       tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+       const char *p = IDENTIFIER_POINTER (id);
+       if (strcmp (p, "allocator") != 0 && strcmp (p, "align") != 0)
+         break;
+       cp_lexer_consume_token (parser->lexer);
+       matching_parens parens2;
+       if (!parens2.require_open (parser))
+         break;
+       if (strcmp (p, "allocator") == 0)
+         {
+           if (allocator != NULL_TREE)
+             break;
+           allocator = cp_parser_assignment_expression (parser);
+         }
+       else
+         {
+           if (align != NULL_TREE)
+             break;
+           align = cp_parser_assignment_expression (parser);
+         }
+       if (!parens2.require_close (parser))
+         break;
+       if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
+         {
+           has_modifiers = true;
+           break;
+         }
+       if (mod != 0 || cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
+         break;
+       cp_lexer_consume_token (parser->lexer);
+      }
+    else
+      break;
+  if (!has_modifiers)
+    {
+      cp_parser_abort_tentative_parse (parser);
+      align = NULL_TREE;
+      allocator = NULL_TREE;
+      cp_parser_parse_tentatively (parser);
+      allocator = cp_parser_assignment_expression (parser);
+    }
   parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
   if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
     {
@@ -38111,18 +38163,25 @@ cp_parser_omp_clause_allocate (cp_parser *parser, tree list)
       cp_lexer_consume_token (parser->lexer);
       if (allocator == error_mark_node)
        allocator = NULL_TREE;
+      if (align == error_mark_node)
+       align = NULL_TREE;
     }
   else
     {
       cp_parser_abort_tentative_parse (parser);
       allocator = NULL_TREE;
+      align = NULL_TREE;
     }
 
   nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_ALLOCATE, list,
                                          &colon);
 
-  for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c))
-    OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) = allocator;
+  if (allocator || align)
+    for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c))
+      {
+       OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) = allocator;
+       OMP_CLAUSE_ALLOCATE_ALIGN (c) = align;
+      }
 
   return nlist;
 }
index a74722de8ba01ffb588a79cadf70e26907d73f4b..1dde98f11e4a7e8bc1cb88c8d4dab8d1aa5585bd 100644 (file)
@@ -17510,6 +17510,13 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort,
          break;
        case OMP_CLAUSE_GANG:
        case OMP_CLAUSE_ALIGNED:
+         OMP_CLAUSE_DECL (nc)
+           = tsubst_omp_clause_decl (OMP_CLAUSE_DECL (oc), args, complain,
+                                     in_decl, NULL);
+         OMP_CLAUSE_OPERAND (nc, 1)
+           = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 1), args, complain,
+                          in_decl, /*integral_constant_expression_p=*/false);
+         break;
        case OMP_CLAUSE_ALLOCATE:
          OMP_CLAUSE_DECL (nc)
            = tsubst_omp_clause_decl (OMP_CLAUSE_DECL (oc), args, complain,
@@ -17517,6 +17524,9 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort,
          OMP_CLAUSE_OPERAND (nc, 1)
            = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 1), args, complain,
                           in_decl, /*integral_constant_expression_p=*/false);
+         OMP_CLAUSE_OPERAND (nc, 2)
+           = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 2), args, complain,
+                          in_decl, /*integral_constant_expression_p=*/false);
          break;
        case OMP_CLAUSE_LINEAR:
          OMP_CLAUSE_DECL (nc)
index 4170621f7fca3f19ef6ac3e8c054898fdf2148b1..f494711319aad882d85a11c3186cca663a901db1 100644 (file)
@@ -7585,7 +7585,44 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
              bitmap_set_bit (&aligned_head, DECL_UID (t));
              allocate_seen = true;
            }
-         tree allocator;
+         tree allocator, align;
+         align = OMP_CLAUSE_ALLOCATE_ALIGN (c);
+         if (error_operand_p (align))
+           {
+             remove = true;
+             break;
+           }
+         if (align)
+           {
+             if (!type_dependent_expression_p (align)
+                 && !INTEGRAL_TYPE_P (TREE_TYPE (align)))
+               {
+                 error_at (OMP_CLAUSE_LOCATION (c),
+                           "%<allocate%> clause %<align%> modifier "
+                           "argument needs to be positive constant "
+                           "power of two integer expression");
+                 remove = true;
+               }
+             else
+               {
+                 align = mark_rvalue_use (align);
+                 if (!processing_template_decl)
+                   {
+                     align = maybe_constant_value (align);
+                     if (TREE_CODE (align) != INTEGER_CST
+                         || !tree_fits_uhwi_p (align)
+                         || !integer_pow2p (align))
+                       {
+                         error_at (OMP_CLAUSE_LOCATION (c),
+                                   "%<allocate%> clause %<align%> modifier "
+                                   "argument needs to be positive constant "
+                                   "power of two integer expression");
+                         remove = true;
+                       }
+                   }
+               }
+             OMP_CLAUSE_ALLOCATE_ALIGN (c) = align;
+           }
          allocator = OMP_CLAUSE_ALLOCATE_ALLOCATOR (c);
          if (error_operand_p (allocator))
            {
@@ -7610,6 +7647,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
                        "type %qT rather than %<omp_allocator_handle_t%>",
                        TREE_TYPE (allocator));
              remove = true;
+             break;
            }
          else
            {
index d4e263c33ac325b3980bbcb04b1af1745db8c716..1eeb6dbebcfb93ab82f53e4be537ad5c3c082230 100644 (file)
@@ -1294,14 +1294,17 @@ scan_sharing_clauses (tree clauses, omp_context *ctx,
     if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_ALLOCATE
        && (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) == NULL_TREE
            /* omp_default_mem_alloc is 1 */
-           || !integer_onep (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c))))
+           || !integer_onep (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c))
+           || OMP_CLAUSE_ALLOCATE_ALIGN (c) != NULL_TREE))
       {
        if (ctx->allocate_map == NULL)
          ctx->allocate_map = new hash_map<tree, tree>;
-       ctx->allocate_map->put (OMP_CLAUSE_DECL (c),
-                               OMP_CLAUSE_ALLOCATE_ALLOCATOR (c)
-                               ? OMP_CLAUSE_ALLOCATE_ALLOCATOR (c)
-                               : integer_zero_node);
+       tree val = integer_zero_node;
+       if (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c))
+         val = OMP_CLAUSE_ALLOCATE_ALLOCATOR (c);
+       if (OMP_CLAUSE_ALLOCATE_ALIGN (c))
+         val = build_tree_list (val, OMP_CLAUSE_ALLOCATE_ALIGN (c));
+       ctx->allocate_map->put (OMP_CLAUSE_DECL (c), val);
       }
 
   for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
@@ -5048,6 +5051,12 @@ lower_private_allocate (tree var, tree new_var, tree &allocator,
       return false;
     }
 
+  unsigned HOST_WIDE_INT ialign = 0;
+  if (TREE_CODE (allocator) == TREE_LIST)
+    {
+      ialign = tree_to_uhwi (TREE_VALUE (allocator));
+      allocator = TREE_PURPOSE (allocator);
+    }
   if (TREE_CODE (allocator) != INTEGER_CST)
     allocator = build_outer_var_ref (allocator, ctx);
   allocator = fold_convert (pointer_sized_int_node, allocator);
@@ -5062,21 +5071,21 @@ lower_private_allocate (tree var, tree new_var, tree &allocator,
   if (TYPE_P (new_var))
     {
       ptr_type = build_pointer_type (new_var);
-      align = build_int_cst (size_type_node, TYPE_ALIGN_UNIT (new_var));
+      ialign = MAX (ialign, TYPE_ALIGN_UNIT (new_var));
     }
   else if (is_ref)
     {
       ptr_type = build_pointer_type (TREE_TYPE (TREE_TYPE (new_var)));
-      align = build_int_cst (size_type_node,
-                            TYPE_ALIGN_UNIT (TREE_TYPE (ptr_type)));
+      ialign = MAX (ialign, TYPE_ALIGN_UNIT (TREE_TYPE (ptr_type)));
     }
   else
     {
       ptr_type = build_pointer_type (TREE_TYPE (new_var));
-      align = build_int_cst (size_type_node, DECL_ALIGN_UNIT (new_var));
+      ialign = MAX (ialign, DECL_ALIGN_UNIT (new_var));
       if (sz == NULL_TREE)
        sz = fold_convert (size_type_node, DECL_SIZE_UNIT (new_var));
     }
+  align = build_int_cst (size_type_node, ialign);
   if (TREE_CODE (sz) != INTEGER_CST)
     {
       tree szvar = create_tmp_var (size_type_node);
@@ -6030,6 +6039,8 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
                    if (tree *allocatep = ctx->allocate_map->get (var))
                      {
                        allocator = *allocatep;
+                       if (TREE_CODE (allocator) == TREE_LIST)
+                         allocator = TREE_PURPOSE (allocator);
                        if (TREE_CODE (allocator) != INTEGER_CST)
                          allocator = build_outer_var_ref (allocator, ctx);
                        allocator = fold_convert (pointer_sized_int_node,
@@ -6348,6 +6359,8 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
                        if (tree *allocatep = ctx->allocate_map->get (var))
                          {
                            allocator = *allocatep;
+                           if (TREE_CODE (allocator) == TREE_LIST)
+                             allocator = TREE_PURPOSE (allocator);
                            if (TREE_CODE (allocator) != INTEGER_CST)
                              allocator = build_outer_var_ref (allocator, ctx);
                            allocator = fold_convert (pointer_sized_int_node,
@@ -12282,6 +12295,12 @@ create_task_copyfn (gomp_task *task_stmt, omp_context *ctx)
              if (tree *allocatorp = ctx->allocate_map->get (decl))
                {
                  tree allocator = *allocatorp;
+                 HOST_WIDE_INT ialign = 0;
+                 if (TREE_CODE (allocator) == TREE_LIST)
+                   {
+                     ialign = tree_to_uhwi (TREE_VALUE (allocator));
+                     allocator = TREE_PURPOSE (allocator);
+                   }
                  if (TREE_CODE (allocator) != INTEGER_CST)
                    {
                      n = splay_tree_lookup (ctx->sfield_map,
@@ -12295,7 +12314,8 @@ create_task_copyfn (gomp_task *task_stmt, omp_context *ctx)
                  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));
+                                             MAX (ialign,
+                                                  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);
index 2d414ab4ae671cea6e673249909fbd670882e7a1..3138d9893a9e05603adcbfbb75b8db2c3cbe380f 100644 (file)
@@ -1,3 +1,12 @@
+2021-09-22  Tobias Burnus  <tobias@codesourcery.com>
+
+       Backported from master:
+       2021-09-22  Jakub Jelinek  <jakub@redhat.com>
+
+       * c-c++-common/gomp/allocate-6.c: New test.
+       * c-c++-common/gomp/allocate-7.c: New test.
+       * g++.dg/gomp/allocate-4.C: New test.
+
 2021-09-21  Tobias Burnus  <tobias@codesourcery.com>
 
        Backported from master:
diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-6.c b/gcc/testsuite/c-c++-common/gomp/allocate-6.c
new file mode 100644 (file)
index 0000000..059fd72
--- /dev/null
@@ -0,0 +1,84 @@
+typedef enum omp_allocator_handle_t
+#if __cplusplus >= 201103L
+: __UINTPTR_TYPE__
+#endif
+{
+  omp_null_allocator = 0,
+  omp_default_mem_alloc = 1,
+  omp_large_cap_mem_alloc = 2,
+  omp_const_mem_alloc = 3,
+  omp_high_bw_mem_alloc = 4,
+  omp_low_lat_mem_alloc = 5,
+  omp_cgroup_mem_alloc = 6,
+  omp_pteam_mem_alloc = 7,
+  omp_thread_mem_alloc = 8,
+  __omp_allocator_handle_t_max__ = __UINTPTR_MAX__
+} omp_allocator_handle_t;
+
+int bar (int, int *, int);
+omp_allocator_handle_t baz (void);
+
+void
+foo (int x, int z)
+{
+  int y[16] = { 0 }, r = 0, i;
+  omp_allocator_handle_t h = baz ();
+  #pragma omp parallel allocate (align (sizeof (int)) : x) allocate (allocator (omp_default_mem_alloc) : y) \
+             allocate (align (8), allocator ((omp_allocator_handle_t) omp_default_mem_alloc):z) firstprivate (x, y, z)
+  bar (x, y, z);
+  #pragma omp task private (x) firstprivate (z) allocate (allocator (omp_low_lat_mem_alloc) :x,z)
+  bar (0, &x, z);
+  #pragma omp taskwait
+  #pragma omp target teams distribute parallel for private (x) firstprivate (y) \
+             allocate (allocator ((omp_allocator_handle_t)(omp_default_mem_alloc + 0)), align (16) : z) \
+             allocate (allocator (omp_default_mem_alloc) : x, y) allocate (align (32), allocator (omp_low_lat_mem_alloc): r) \
+             lastprivate (z) reduction(+:r)
+  for (i = 0; i < 64; i++)
+    {
+      z = bar (0, &x, 0);
+      r += bar (1, y, 0);
+    }
+  #pragma omp single private (x) allocate (allocator (h):x)
+  ;
+  #pragma omp single allocate (align (2 * sizeof (int)), allocator (*&h) : x) private (x)
+  ;
+  #pragma omp parallel shared (r, x, z)
+  #pragma omp single firstprivate (r) allocate (align (4) : x, r, z) private (x, z)
+  ;
+  #pragma omp for allocate (align (2 * 2 * 2) : x) private (x)
+  for (i = 0; i < 64; i++)
+    x = 1;
+  #pragma omp sections private (x) allocate (allocator (omp_low_lat_mem_alloc), align (8): x)
+  {
+    x = 1;
+    #pragma omp section
+    x = 2;
+    #pragma omp section
+    x = 3;
+  }
+  #pragma omp taskgroup task_reduction(+:r) allocate (allocator (omp_default_mem_alloc), align (__alignof (r)) : r)
+  #pragma omp task in_reduction(+:r) allocate (align (2 * sizeof (r)), allocator (omp_default_mem_alloc) : r)
+  r += bar (r, &r, 0);
+  #pragma omp teams private (x) firstprivate (y) allocate (allocator (h), align (8) : x, y)
+  bar (x, y, 0);
+  #pragma omp taskloop lastprivate (x) reduction (+:r) allocate (align (16), allocator (h) : x, r)
+  for (i = 0; i < 16; i++)
+    {
+      r += bar (0, &r, 0);
+      x = i;
+    }
+  #pragma omp taskgroup task_reduction(+:r) allocate (allocator (omp_default_mem_alloc), align (64) : r)
+  #pragma omp taskloop firstprivate (x) in_reduction (+:r) \
+                      allocate (allocator (omp_default_mem_alloc), align (128) : x, r)
+  for (i = 0; i < 16; i++)
+    r += bar (x, &r, 0);
+  #pragma omp taskwait
+}
+
+void
+qux (const omp_allocator_handle_t h)
+{
+  int x = 0;
+  #pragma omp parallel firstprivate (x) allocate (align (16), allocator (h): x)
+  x = 1;
+}
diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-7.c b/gcc/testsuite/c-c++-common/gomp/allocate-7.c
new file mode 100644 (file)
index 0000000..d125d92
--- /dev/null
@@ -0,0 +1,41 @@
+typedef enum omp_allocator_handle_t
+#if __cplusplus >= 201103L
+: __UINTPTR_TYPE__
+#endif
+{
+  omp_null_allocator = 0,
+  omp_default_mem_alloc = 1,
+  omp_large_cap_mem_alloc = 2,
+  omp_const_mem_alloc = 3,
+  omp_high_bw_mem_alloc = 4,
+  omp_low_lat_mem_alloc = 5,
+  omp_cgroup_mem_alloc = 6,
+  omp_pteam_mem_alloc = 7,
+  omp_thread_mem_alloc = 8,
+  __omp_allocator_handle_t_max__ = __UINTPTR_MAX__
+} omp_allocator_handle_t;
+
+int bar (int *);
+omp_allocator_handle_t baz (void);
+
+void
+foo (int x, int z)
+{
+  int i;
+  #pragma omp parallel private (x) allocate (allocator (0.0) : x)      /* { dg-error "'allocate' clause allocator expression has type 'double' rather than 'omp_allocator_handle_t'" } */
+  bar (&x);
+  #pragma omp parallel private (x) allocate (allocator (0) : x)        /* { dg-error "'allocate' clause allocator expression has type 'int' rather than 'omp_allocator_handle_t'" } */
+  bar (&x);
+  #pragma omp parallel private (x) allocate (align (z) : x)    /* { dg-error "'allocate' clause 'align' modifier argument needs to be positive constant power of two integer expression" } */
+  bar (&x);
+  #pragma omp parallel private (x) allocate (align (16.0) : x) /* { dg-error "'allocate' clause 'align' modifier argument needs to be positive constant power of two integer expression" } */
+  bar (&x);
+  #pragma omp parallel private (x) allocate (align (14) : x)   /* { dg-error "'allocate' clause 'align' modifier argument needs to be positive constant power of two integer expression" } */
+  bar (&x);
+  #pragma omp parallel private (x) allocate (align (0) : x)    /* { dg-error "'allocate' clause 'align' modifier argument needs to be positive constant power of two integer expression" } */
+  bar (&x);
+  #pragma omp parallel private (x) allocate (align (16), align (16) : x)       /* { dg-error "expected|duplicate|declared|specified" } */
+  bar (&x);                                                                    /* { dg-warning "more than once" "" { target c++ } .-1 } */
+  #pragma omp parallel private (x) allocate (allocator (omp_default_mem_alloc), allocator (omp_default_mem_alloc) : x) /* { dg-error "expected|duplicate|declared|specified" } */
+  bar (&x);                                                                    /* { dg-warning "more than once" "" { target c++ } .-1 } */
+}
diff --git a/gcc/testsuite/g++.dg/gomp/allocate-4.C b/gcc/testsuite/g++.dg/gomp/allocate-4.C
new file mode 100644 (file)
index 0000000..dd5e5f0
--- /dev/null
@@ -0,0 +1,108 @@
+// { dg-do compile }
+// { dg-additional-options "-std=c++11" }
+
+typedef enum omp_allocator_handle_t
+#if __cplusplus >= 201103L
+: __UINTPTR_TYPE__
+#endif
+{
+  omp_null_allocator = 0,
+  omp_default_mem_alloc = 1,
+  omp_large_cap_mem_alloc = 2,
+  omp_const_mem_alloc = 3,
+  omp_high_bw_mem_alloc = 4,
+  omp_low_lat_mem_alloc = 5,
+  omp_cgroup_mem_alloc = 6,
+  omp_pteam_mem_alloc = 7,
+  omp_thread_mem_alloc = 8,
+  __omp_allocator_handle_t_max__ = __UINTPTR_MAX__
+} omp_allocator_handle_t;
+
+namespace N1
+{
+  using ::omp_allocator_handle_t;
+  void
+  foo (const omp_allocator_handle_t h)
+  {
+    int x = 0;
+    #pragma omp parallel allocate (allocator (h): x) private (x)
+    x = 1;
+  }
+}
+
+namespace N2
+{
+  typedef enum omp_allocator_handle_t { my = 0 } omp_allocator_handle_t;
+  void
+  foo (omp_allocator_handle_t h)
+  {
+    int x = 0;
+    #pragma omp parallel allocate (allocator (h): x) private (x) // { dg-error "'allocate' clause allocator expression has type 'N2::omp_allocator_handle_t' rather than 'omp_allocator_handle_t'" }
+    x = 1;
+  }
+}
+
+struct S
+{
+  void foo ()
+  {
+    #pragma omp parallel allocate (allocator(omp_default_mem_alloc):s) firstprivate (s)
+    s++;
+  }
+  int s;
+};
+
+template <typename T>
+struct U
+{
+  int foo ()
+  {
+    #pragma omp parallel allocate (allocator(omp_default_mem_alloc):s) firstprivate (s)
+    s++;
+    return 1;
+  }
+  T s;
+};
+
+template <typename T, int N>
+int foo (T t)
+{
+  int x = 0;
+  #pragma omp parallel firstprivate (x) allocate (allocator(t), align (N): x)
+  x = 1;
+  return 0;
+}
+
+template <typename T>
+int bar (T t)
+{
+  int x = 0;
+  #pragma omp parallel firstprivate (x) allocate (allocator(t): x)     // { dg-error "'allocate' clause allocator expression has type 'int' rather than 'omp_allocator_handle_t'" }
+  x = 1;
+  return 0;
+}
+
+template <typename T, int N>
+int baz (T t)
+{
+  int x = 0;
+  #pragma omp parallel firstprivate (x) allocate (allocator(t), align (N): x) // { dg-error "'allocate' clause 'align' modifier argument needs to be positive constant power of two integer expression" }
+  x = 1;
+  return 0;
+}
+
+template <typename T>
+int qux ()
+{
+  int x = 0;
+  #pragma omp parallel firstprivate (x) allocate (align ((T) 16): x) // { dg-error "'allocate' clause 'align' modifier argument needs to be positive constant power of two integer expression" }
+  x = 1;
+  return 0;
+}
+
+omp_allocator_handle_t h;
+int a = foo<omp_allocator_handle_t, 16> (h);
+int b = bar (0);
+int c = U<int> ().foo ();
+int d = baz<omp_allocator_handle_t, 13> (h);
+int e = qux<long double> ();
index 04f7205f1e5fdbb28b7fcdd0c06f2b7e4c1a117c..163566beaaa8ce3f14a622ce44b63084b32701c6 100644 (file)
@@ -735,10 +735,23 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags)
       pp_string (pp, "allocate(");
       if (OMP_CLAUSE_ALLOCATE_ALLOCATOR (clause))
        {
+         pp_string (pp, "allocator(");
          dump_generic_node (pp, OMP_CLAUSE_ALLOCATE_ALLOCATOR (clause),
                             spc, flags, false);
-         pp_colon (pp);
+         pp_right_paren (pp);
+       }
+      if (OMP_CLAUSE_ALLOCATE_ALIGN (clause))
+       {
+         if (OMP_CLAUSE_ALLOCATE_ALLOCATOR (clause))
+           pp_comma (pp);
+         pp_string (pp, "align(");
+         dump_generic_node (pp, OMP_CLAUSE_ALLOCATE_ALIGN (clause),
+                            spc, flags, false);
+         pp_right_paren (pp);
        }
+      if (OMP_CLAUSE_ALLOCATE_ALLOCATOR (clause)
+         || OMP_CLAUSE_ALLOCATE_ALIGN (clause))
+       pp_colon (pp);
       dump_generic_node (pp, OMP_CLAUSE_DECL (clause),
                         spc, flags, false);
       pp_right_paren (pp);
index e49f4b808831860292a035e97776ed93b1d5716a..7320247e05f881ad64d184141aa104a21c65825d 100644 (file)
@@ -292,7 +292,7 @@ unsigned const char omp_clause_num_ops[] =
   3, /* OMP_CLAUSE_LINEAR  */
   1, /* OMP_CLAUSE_AFFINITY  */
   2, /* OMP_CLAUSE_ALIGNED  */
-  2, /* OMP_CLAUSE_ALLOCATE  */
+  3, /* OMP_CLAUSE_ALLOCATE  */
   1, /* OMP_CLAUSE_DEPEND  */
   1, /* OMP_CLAUSE_NONTEMPORAL  */
   1, /* OMP_CLAUSE_UNIFORM  */
index 39f7e7c8ded33abcea58384898c3906da68b0bad..f8853dfb7506dd1321ce9b716dd7755aa19bd967 100644 (file)
@@ -1802,6 +1802,9 @@ class auto_suppress_location_wrappers
 #define OMP_CLAUSE_ALLOCATE_ALLOCATOR(NODE) \
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ALLOCATE), 1)
 
+#define OMP_CLAUSE_ALLOCATE_ALIGN(NODE) \
+  OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ALLOCATE), 2)
+
 /* True if an ALLOCATE clause was present on a combined or composite
    construct and the code for splitting the clauses has already performed
    checking if the listed variable has explicit privatization on the
index ecaa26cf45f1b901b7f3b804c49220ee4ed47e27..223961ffe57b06c6428345c7dfc46145192436e9 100644 (file)
@@ -1,3 +1,11 @@
+2021-09-22  Tobias Burnus  <tobias@codesourcery.com>
+
+       Backported from master:
+       2021-09-22  Jakub Jelinek  <jakub@redhat.com>
+
+       * testsuite/libgomp.c-c++-common/allocate-2.c: New test.
+       * testsuite/libgomp.c-c++-common/allocate-3.c: New test.
+
 2021-09-21  Tobias Burnus  <tobias@codesourcery.com>
 
        Backported from master:
diff --git a/libgomp/testsuite/libgomp.c-c++-common/allocate-2.c b/libgomp/testsuite/libgomp.c-c++-common/allocate-2.c
new file mode 100644 (file)
index 0000000..e4cd09a
--- /dev/null
@@ -0,0 +1,37 @@
+#include <omp.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+int zero;
+
+omp_allocator_handle_t
+allocator (omp_allocator_handle_t h)
+{
+  if (zero)
+    return h;
+  else
+    abort ();
+}
+
+omp_allocator_handle_t
+align (int a)
+{
+  if (zero)
+    return omp_default_mem_alloc;
+  else
+    abort ();
+}
+
+int
+main ()
+{
+  int x = 1, y = 2;
+  #pragma omp parallel num_threads(2) firstprivate (x, y) allocate (allocator (omp_default_mem_alloc) : x) allocate (align (16) : y)
+  {
+    if (x != 1 || y != 2)
+      abort ();
+    if ((((uintptr_t) &y) & 15) != 0)
+      abort ();
+  }
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/allocate-3.c b/libgomp/testsuite/libgomp.c-c++-common/allocate-3.c
new file mode 100644 (file)
index 0000000..ce1a045
--- /dev/null
@@ -0,0 +1,405 @@
+#include <omp.h>
+#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)
+{
+  int y = 0, r = 0, i, i1, l, l2[4], l3, n = 8;
+  int i2, j2, n2 = 9, l4;
+  int i3, j3, n3 = 10, l5;
+  int i4, j4, n4 = 11, l6;
+  int i5;
+  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++)
+    q[i] = 0;
+  for (i = 0; i < x; i++)
+    w[i] = i;
+  #pragma omp parallel private (y, v) firstprivate (x) allocate (align (32) : x) allocate (align (128) : y) allocate (v)
+  {
+    int *volatile p1 = &x;
+    int *volatile p2 = &y;
+    if (x != 42)
+      abort ();
+    #pragma omp barrier
+    *p2 = 1;
+    p1[0]++;
+    v[0] = 7;
+    v[41] = 8;
+    #pragma omp barrier
+    if (x != 43 || y != 1)
+      abort ();
+    if (v[0] != 7 || v[41] != 8)
+      abort ();
+    if ((fl & 2) && (((uintptr_t) p1 | (uintptr_t) p2
+       | (uintptr_t) &v[0]) & 63) != 0)
+      abort ();
+    if ((((uintptr_t) p1) & 31) != 0)
+      abort ();
+    if ((((uintptr_t) p2) & 127) != 0)
+      abort ();
+  }
+  x = xo;
+  #pragma omp teams
+  #pragma omp parallel private (y) firstprivate (x, w) allocate (allocator (h), align (32) : x) allocate (align (128), allocator (h):y) allocate(allocator(h):w)
+  {
+    int *volatile p1 = &x;
+    int *volatile p2 = &y;
+    if (x != 42 || w[17] != 17 || w[41] != 41)
+      abort ();
+    #pragma omp barrier
+    *p2 = 1;
+    p1[0]++;
+    w[19]++;
+    #pragma omp barrier
+    if (x != 43 || y != 1 || w[19] != 20)
+      abort ();
+    if ((fl & 1) && (((uintptr_t) p1 | (uintptr_t) p2
+                     | (uintptr_t) &w[0]) & 63) != 0)
+      abort ();
+    if ((((uintptr_t) p1) & 31) != 0)
+      abort ();
+    if ((((uintptr_t) p2) & 127) != 0)
+      abort ();
+  }
+  x = xo;
+  #pragma omp parallel for private (y) firstprivate (x) allocate (allocator (h), align (32) : x, y, r) allocate (align (128), allocator (h) : l, n) reduction(+: r) lastprivate (l) linear (n: 16)
+  for (i = 0; i < 64; i++)
+    {
+      if (x != 42)
+       abort ();
+      y = 1;
+      l = i;
+      n += y + 15;
+      r += i;
+      if ((fl & 1) && (((uintptr_t) &x | (uintptr_t) &y | (uintptr_t) &r
+                       | (uintptr_t) &l | (uintptr_t) &n) & 63) != 0)
+       abort ();
+      if ((((uintptr_t) &x | (uintptr_t) &y | (uintptr_t) &r) & 31) != 0)
+       abort ();
+      if ((((uintptr_t) &l | (uintptr_t) &n) & 127) != 0)
+       abort ();
+    }
+  x = xo;
+  #pragma omp parallel
+  {
+    #pragma omp for lastprivate (l2) private (i1) allocate (allocator (h): l2, l3) allocate (allocator (h),align(16): i1) lastprivate (conditional: l3)
+    for (i1 = 0; i1 < 64; i1++)
+      {
+       l2[0] = i1;
+       l2[1] = i1 + 1;
+       l2[2] = i1 + 2;
+       l2[3] = i1 + 3;
+       if (i1 < 37)
+         l3 = i1;
+       if ((fl & 1) && (((uintptr_t) &l2[0] | (uintptr_t) &l3 | (uintptr_t) &i1) & 63) != 0)
+         abort ();
+       if ((((uintptr_t) &i1) & 15) != 0)
+         abort ();
+      }
+    #pragma omp for collapse(2) lastprivate(l4, i2, j2) linear (n2:17) allocate (allocator (h), align (8): n2, l4, i2, j2)
+    for (i2 = 3; i2 < 5; i2++)
+      for (j2 = 17; j2 < 22; j2 += 2)
+       {
+         n2 += 17;
+         l4 = i2 * 31 + j2;
+         if ((fl & 1) && (((uintptr_t) &l4 | (uintptr_t) &n2
+                           | (uintptr_t) &i2 | (uintptr_t) &j2) & 63) != 0)
+           abort ();
+         if ((((uintptr_t) &l4 | (uintptr_t) &n2 | (uintptr_t) &i2 | (uintptr_t) &j2) & 7) != 0)
+           abort ();
+       }
+    #pragma omp for collapse(2) lastprivate(l5, i3, j3) linear (n3:17) schedule (static, 3) allocate (align (16): n3, l5, i3, j3)
+    for (i3 = 3; i3 < 5; i3++)
+      for (j3 = 17; j3 < 23; j3 += 2)
+       {
+         n3 += 17;
+         l5 = i3 * 31 + j3;
+         if ((fl & 2) && (((uintptr_t) &l5 | (uintptr_t) &n3
+                           | (uintptr_t) &i3 | (uintptr_t) &j3) & 63) != 0)
+           abort ();
+         if ((((uintptr_t) &l5 | (uintptr_t) &n3 | (uintptr_t) &i3 | (uintptr_t) &j3) & 15) != 0)
+           abort ();
+       }
+    #pragma omp for collapse(2) lastprivate(l6, i4, j4) linear (n4:17) schedule (dynamic) allocate (align (16), allocator (h): n4, l6, i4, j4)
+    for (i4 = 3; i4 < 5; i4++)
+      for (j4 = 17; j4 < 22; j4 += 2)
+       {
+         n4 += 17;
+         l6 = i4 * 31 + j4;
+         if ((fl & 1) && (((uintptr_t) &l6 | (uintptr_t) &n4
+                           | (uintptr_t) &i4 | (uintptr_t) &j4) & 63) != 0)
+           abort ();
+         if ((((uintptr_t) &l6 | (uintptr_t) &n4 | (uintptr_t) &i4 | (uintptr_t) &j4) & 15) != 0)
+           abort ();
+       }
+    #pragma omp for lastprivate (i5) allocate (align (32): i5)
+    for (i5 = 1; i5 < 17; i5 += 3)
+      {
+       if ((fl & 2) && (((uintptr_t) &i5) & 63) != 0)
+         abort ();
+       if ((((uintptr_t) &i5) & 31) != 0)
+         abort ();
+      }
+    #pragma omp for reduction(+:p[2:px], q[:3], r2) allocate(align (16), allocator (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 ();
+       if ((((uintptr_t) &q[0] | (uintptr_t) &r2[0]) & 15) != 0)
+         abort ();
+      }
+    #pragma omp task private(y) firstprivate(x) allocate(align (8) : 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 ();
+      if ((((uintptr_t) p1 | (uintptr_t) p2) & 7) != 0)
+       abort ();
+    }
+    #pragma omp task private(y) firstprivate(x) allocate(allocator (h),align(32): 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 ();
+      if ((((uintptr_t) p1 | (uintptr_t) p2) & 31) != 0)
+       abort ();
+    }
+    #pragma omp task private(y) firstprivate(s) allocate(align(16): 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 ();
+      if ((((uintptr_t) p1 | (uintptr_t) p3) & 15) != 0)
+       abort ();
+    }
+    #pragma omp task private(y) firstprivate(s) allocate(allocator (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 ();
+  if (l2[0] != 63 || l2[1] != 63 + 1 || l2[2] != 63 + 2 || l2[3] != 63 + 3 || l3 != 36)
+    abort ();
+  if (i2 != 5 || j2 != 23 || n2 != 9 + 6 * 17 || l4 != 4 * 31 + 21)
+    abort ();
+  if (i3 != 5 || j3 != 23 || n3 != 10 + 6 * 17 || l5 != 4 * 31 + 21)
+    abort ();
+  if (i4 != 5 || j4 != 23 || n4 != 11 + 6 * 17 || l6 != 4 * 31 + 21)
+    abort ();
+  if (i5 != 19)
+    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 ();
+}
+
+void
+bar (int x, omp_allocator_handle_t h)
+{
+  int y = 0, r = 0, i, i1, l, l2[4], l3, n = 8;
+  int i2, j2, n2 = 9, l4;
+  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)
+  {
+    if (x != 42)
+      abort ();
+    #pragma omp barrier
+    y = 1;
+    x++;
+    #pragma omp barrier
+    if (x != 43 || y != 1)
+      abort ();
+  }
+  x = xo;
+  #pragma omp teams
+  #pragma omp parallel private (y) firstprivate (x) allocate (allocator (h): x, y)
+  {
+    if (x != 42)
+      abort ();
+    #pragma omp barrier
+    y = 1;
+    x++;
+    #pragma omp barrier
+    if (x != 43 || y != 1)
+      abort ();
+  }
+  x = xo;
+  #pragma omp parallel for private (y) firstprivate (x) allocate (allocator (h): x, y, r, l, n) reduction(+: r) lastprivate (l) linear (n: 16)
+  for (i = 0; i < 64; i++)
+    {
+      if (x != 42)
+       abort ();
+      y = 1;
+      l = i;
+      n += y + 15;
+      r += i;
+    }
+  x = xo;
+  #pragma omp parallel
+  {
+    #pragma omp for lastprivate (l2) private (i1) allocate (allocator (h): l2, l3, i1) lastprivate (conditional: l3)
+    for (i1 = 0; i1 < 64; i1++)
+      {
+       l2[0] = i1;
+       l2[1] = i1 + 1;
+       l2[2] = i1 + 2;
+       l2[3] = i1 + 3;
+       if (i1 < 37)
+         l3 = i1;
+      }
+    #pragma omp for collapse(2) lastprivate(l4, i2, j2) linear (n2:17) allocate (allocator (h): n2, l4, i2, j2)
+    for (i2 = 3; i2 < 5; i2++)
+      for (j2 = 17; j2 < 22; j2 += 2)
+       {
+         n2 += 17;
+         l4 = i2 * 31 + j2;
+       }
+    #pragma omp for collapse(2) lastprivate(l5, i3, j3) linear (n3:17) schedule (static, 3) allocate (n3, l5, i3, j3)
+    for (i3 = 3; i3 < 5; i3++)
+      for (j3 = 17; j3 < 23; j3 += 2)
+       {
+         n3 += 17;
+         l5 = i3 * 31 + j3;
+       }
+    #pragma omp for collapse(2) lastprivate(l6, i4, j4) linear (n4:17) schedule (dynamic) allocate (allocator (h): n4, l6, i4, j4)
+    for (i4 = 3; i4 < 5; i4++)
+      for (j4 = 17; j4 < 22; j4 += 2)
+       {
+         n4 += 17;
+         l6 = i4 * 31 + j4;
+       }
+    #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(allocator (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(allocator (h), align (16): 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 ();
+  if (l2[0] != 63 || l2[1] != 63 + 1 || l2[2] != 63 + 2 || l2[3] != 63 + 3 || l3 != 36)
+    abort ();
+  if (i2 != 5 || j2 != 23 || n2 != 9 + 6 * 17 || l4 != 4 * 31 + 21)
+    abort ();
+  if (i3 != 5 || j3 != 23 || n3 != 10 + 6 * 17 || l5 != 4 * 31 + 21)
+    abort ();
+  if (i4 != 5 || j4 != 23 || n4 != 11 + 6 * 17 || l6 != 4 * 31 + 21)
+    abort ();
+  if (i5 != 19)
+    abort ();
+}
+
+int
+main ()
+{
+  omp_alloctrait_t traits[3]
+    = { { omp_atk_alignment, 64 },
+       { omp_atk_fallback, omp_atv_null_fb } };
+  omp_allocator_handle_t a
+    = omp_init_allocator (omp_default_mem_space, 2, traits);
+  int p[4], q[3];
+  if (a == omp_null_allocator)
+    abort ();
+  omp_set_default_allocator (omp_default_mem_alloc);
+  foo (42, p, q, 2, omp_null_allocator, 0);
+  foo (42, p, q, 2, omp_default_mem_alloc, 0);
+  foo (42, p, q, 2, a, 1);
+  omp_set_default_allocator (a);
+  foo (42, p, q, 2, omp_null_allocator, 3);
+  foo (42, p, q, 2, omp_default_mem_alloc, 2);
+  bar (42, a);
+  omp_destroy_allocator (a);
+  return 0;
+}