diff mbox series

[committed] openmp: Add support for allocator and align modifiers on allocate clauses

Message ID 20210922073830.GA304296@tucnak
State New
Headers show
Series [committed] openmp: Add support for allocator and align modifiers on allocate clauses | expand

Commit Message

Jakub Jelinek Sept. 22, 2021, 7:38 a.m. UTC
Hi!

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.

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

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.


	Jakub
diff mbox series

Patch

--- gcc/tree.h.jj	2021-09-18 09:58:13.005369028 +0200
+++ gcc/tree.h	2021-09-20 13:22:18.148740810 +0200
@@ -1790,6 +1790,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
--- gcc/tree.c.jj	2021-09-16 10:51:02.295976216 +0200
+++ gcc/tree.c	2021-09-20 13:21:55.597065187 +0200
@@ -291,7 +291,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  */
--- gcc/tree-pretty-print.c.jj	2021-09-18 09:58:13.005369028 +0200
+++ gcc/tree-pretty-print.c	2021-09-20 13:24:52.963514008 +0200
@@ -735,10 +735,23 @@  dump_omp_clause (pretty_printer *pp, tre
       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);
--- gcc/omp-low.c.jj	2021-09-17 18:14:59.217561064 +0200
+++ gcc/omp-low.c	2021-09-20 21:25:35.821855544 +0200
@@ -1161,14 +1161,17 @@  scan_sharing_clauses (tree clauses, omp_
     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))
@@ -4725,6 +4728,12 @@  lower_private_allocate (tree var, tree n
       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);
@@ -4739,21 +4748,21 @@  lower_private_allocate (tree var, tree n
   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);
@@ -5707,6 +5716,8 @@  lower_rec_input_clauses (tree clauses, g
 		    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,
@@ -6025,6 +6036,8 @@  lower_rec_input_clauses (tree clauses, g
 			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,
@@ -12070,6 +12083,12 @@  create_task_copyfn (gomp_task *task_stmt
 	      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,
@@ -12083,7 +12102,8 @@  create_task_copyfn (gomp_task *task_stmt
 		  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);
--- gcc/c-family/c-omp.c.jj	2021-09-18 09:58:12.995369167 +0200
+++ gcc/c-family/c-omp.c	2021-09-21 13:07:05.368124836 +0200
@@ -2511,6 +2511,8 @@  c_omp_split_clauses (location_t loc, enu
 		    = 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;
--- gcc/c/c-parser.c.jj	2021-09-18 09:58:12.997369139 +0200
+++ gcc/c/c-parser.c	2021-09-21 12:12:36.515817261 +0200
@@ -15305,7 +15305,15 @@  c_parser_omp_clause_aligned (c_parser *p
 
 /* 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)
@@ -15313,6 +15321,7 @@  c_parser_omp_clause_allocate (c_parser *
   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))
@@ -15323,17 +15332,128 @@  c_parser_omp_clause_allocate (c_parser *
       || (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 "
@@ -15341,6 +15461,16 @@  c_parser_omp_clause_allocate (c_parser *
 				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);
@@ -15351,9 +15481,12 @@  c_parser_omp_clause_allocate (c_parser *
   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;
--- gcc/cp/parser.c.jj	2021-09-18 09:58:13.003369056 +0200
+++ gcc/cp/parser.c	2021-09-21 13:12:47.966234967 +0200
@@ -38337,13 +38337,21 @@  cp_parser_omp_clause_aligned (cp_parser
 
 /* 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))
@@ -38352,7 +38360,51 @@  cp_parser_omp_clause_allocate (cp_parser
   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))
     {
@@ -38360,18 +38412,25 @@  cp_parser_omp_clause_allocate (cp_parser
       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;
 }
--- gcc/cp/semantics.c.jj	2021-09-17 11:28:07.608834046 +0200
+++ gcc/cp/semantics.c	2021-09-21 11:28:44.898436078 +0200
@@ -7527,7 +7527,44 @@  finish_omp_clauses (tree clauses, enum c
 	      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))
 	    {
@@ -7552,6 +7589,7 @@  finish_omp_clauses (tree clauses, enum c
 			"type %qT rather than %<omp_allocator_handle_t%>",
 			TREE_TYPE (allocator));
 	      remove = true;
+	      break;
 	    }
 	  else
 	    {
--- gcc/cp/pt.c.jj	2021-09-18 09:44:31.738743574 +0200
+++ gcc/cp/pt.c	2021-09-21 11:18:56.181855594 +0200
@@ -17489,6 +17489,13 @@  tsubst_omp_clauses (tree clauses, enum c
 	  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,
@@ -17496,6 +17503,9 @@  tsubst_omp_clauses (tree clauses, enum c
 	  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)
--- gcc/testsuite/c-c++-common/gomp/allocate-6.c.jj	2021-09-21 12:29:26.765382134 +0200
+++ gcc/testsuite/c-c++-common/gomp/allocate-6.c	2021-09-20 14:58:44.115513164 +0200
@@ -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;
+}
--- gcc/testsuite/c-c++-common/gomp/allocate-7.c.jj	2021-09-21 13:34:30.672649357 +0200
+++ gcc/testsuite/c-c++-common/gomp/allocate-7.c	2021-09-21 14:00:51.992112138 +0200
@@ -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 } */
+}
--- gcc/testsuite/g++.dg/gomp/allocate-4.C.jj	2021-09-21 13:47:34.027484007 +0200
+++ gcc/testsuite/g++.dg/gomp/allocate-4.C	2021-09-21 13:52:36.470173384 +0200
@@ -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> ();
--- libgomp/testsuite/libgomp.c-c++-common/allocate-2.c.jj	2021-09-21 12:36:52.488013865 +0200
+++ libgomp/testsuite/libgomp.c-c++-common/allocate-2.c	2021-09-21 12:56:27.437231787 +0200
@@ -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;
+}
--- libgomp/testsuite/libgomp.c-c++-common/allocate-3.c.jj	2021-09-21 12:41:37.736938363 +0200
+++ libgomp/testsuite/libgomp.c-c++-common/allocate-3.c	2021-09-21 12:56:50.510902262 +0200
@@ -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;
+}