public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r13-337] openmp: Add omp_all_memory support (C/C++ only so far)
@ 2022-05-12  6:39 Jakub Jelinek
  0 siblings, 0 replies; only message in thread
From: Jakub Jelinek @ 2022-05-12  6:39 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:7f78783dbedca0183d193e475262ca3c489fd365

commit r13-337-g7f78783dbedca0183d193e475262ca3c489fd365
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Thu May 12 08:31:20 2022 +0200

    openmp: Add omp_all_memory support (C/C++ only so far)
    
    The ugly part is that OpenMP 5.1 made omp_all_memory a reserved identifier
    which isn't allowed to be used anywhere but in the depend clause, this is
    against how everything else has been handled in OpenMP so far (where
    some identifiers could have special meaning in some OpenMP clauses or
    pragmas but not elsewhere).
    The patch handles it by making it a conditional keyword (for -fopenmp
    only) and emitting a better diagnostics when it is used in a primary
    expression.  Having a nicer diagnostics when e.g. trying to do
    int omp_all_memory;
    or
    int *omp_all_memory[10];
    etc. would mean changing too many spots and hooking into name lookups
    to reject declaring any such symbols would be too ugly and I'm afraid
    there are way too many spots where one can introduce a name
    (variables, functions, namespaces, struct, enum, enumerators, template
    arguments, ...).
    
    Otherwise, the handling is quite simple, normal depend clauses lower
    into addresses of variables being handed over to the library, for
    omp_all_memory I'm using NULL pointers.  omp_all_memory can only be
    used with inout or out depend kinds and means that a task is dependent
    on all previously created sibling tasks that have any dependency (of
    any depend kind) and that any later created sibling tasks will be
    dependent on it if they have any dependency.
    
    2022-05-12  Jakub Jelinek  <jakub@redhat.com>
    
    gcc/
            * gimplify.cc (gimplify_omp_depend): Don't build_fold_addr_expr
            if null_pointer_node.
            (gimplify_scan_omp_clauses): Likewise.
            * tree-pretty-print.cc (dump_omp_clause): Print null_pointer_node
            as omp_all_memory.
    gcc/c-family/
            * c-common.h (enum rid): Add RID_OMP_ALL_MEMORY.
            * c-omp.cc (c_finish_omp_depobj): Don't build_fold_addr_expr
            if null_pointer_node.
    gcc/c/
            * c-parser.cc (c_parse_init): Register omp_all_memory as keyword
            if flag_openmp.
            (c_parser_postfix_expression): Diagnose uses of omp_all_memory
            in postfix expressions.
            (c_parser_omp_variable_list): Handle omp_all_memory in depend
            clause.
            * c-typeck.cc (c_finish_omp_clauses): Handle omp_all_memory
            keyword in depend clause as null_pointer_node, diagnose invalid
            uses.
    gcc/cp/
            * lex.cc (init_reswords): Register omp_all_memory as keyword
            if flag_openmp.
            * parser.cc (cp_parser_primary_expression): Diagnose uses of
            omp_all_memory in postfix expressions.
            (cp_parser_omp_var_list_no_open): Handle omp_all_memory in depend
            clause.
            * semantics.cc (finish_omp_clauses): Handle omp_all_memory
            keyword in depend clause as null_pointer_node, diagnose invalid
            uses.
            * pt.cc (tsubst_omp_clause_decl): Pass through omp_all_memory.
    gcc/testsuite/
            * c-c++-common/gomp/all-memory-1.c: New test.
            * c-c++-common/gomp/all-memory-2.c: New test.
            * c-c++-common/gomp/all-memory-3.c: New test.
            * g++.dg/gomp/all-memory-1.C: New test.
            * g++.dg/gomp/all-memory-2.C: New test.
    libgomp/
            * libgomp.h (struct gomp_task): Add depend_all_memory member.
            * task.c (gomp_init_task): Initialize depend_all_memory.
            (gomp_task_handle_depend): Handle omp_all_memory.
            (gomp_task_run_post_handle_depend_hash): Clear
            parent->depend_all_memory if equal to current task.
            (gomp_task_maybe_wait_for_dependencies): Handle omp_all_memory.
            * testsuite/libgomp.c-c++-common/depend-1.c: New test.
            * testsuite/libgomp.c-c++-common/depend-2.c: New test.
            * testsuite/libgomp.c-c++-common/depend-3.c: New test.

Diff:
---
 gcc/c-family/c-common.h                           |   3 +
 gcc/c-family/c-omp.cc                             |   2 +-
 gcc/c/c-parser.cc                                 |  29 +++-
 gcc/c/c-typeck.cc                                 |  44 ++++--
 gcc/cp/lex.cc                                     |   8 ++
 gcc/cp/parser.cc                                  |  17 +++
 gcc/cp/pt.cc                                      |   4 +-
 gcc/cp/semantics.cc                               |  44 ++++--
 gcc/gimplify.cc                                   |  19 ++-
 gcc/testsuite/c-c++-common/gomp/all-memory-1.c    |  52 +++++++
 gcc/testsuite/c-c++-common/gomp/all-memory-2.c    |  55 +++++++
 gcc/testsuite/c-c++-common/gomp/all-memory-3.c    |  22 +++
 gcc/testsuite/g++.dg/gomp/all-memory-1.C          |  24 ++++
 gcc/testsuite/g++.dg/gomp/all-memory-2.C          |  26 ++++
 gcc/tree-pretty-print.cc                          |   5 +-
 libgomp/libgomp.h                                 |   2 +
 libgomp/task.c                                    | 168 +++++++++++++++++++++-
 libgomp/testsuite/libgomp.c-c++-common/depend-1.c | 110 ++++++++++++++
 libgomp/testsuite/libgomp.c-c++-common/depend-2.c | 116 +++++++++++++++
 libgomp/testsuite/libgomp.c-c++-common/depend-3.c | 103 +++++++++++++
 20 files changed, 817 insertions(+), 36 deletions(-)

diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index aa043defe9e..47442c95a53 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -219,6 +219,9 @@ enum rid
   RID_AT_INTERFACE,
   RID_AT_IMPLEMENTATION,
 
+  /* OpenMP */
+  RID_OMP_ALL_MEMORY,
+
   /* Named address support, mapping the keyword to a particular named address
      number.  Named address space 0 is reserved for the generic address.  If
      there are more than 254 named addresses, the addr_space_t type will need
diff --git a/gcc/c-family/c-omp.cc b/gcc/c-family/c-omp.cc
index 777cdc65572..987ba7d724a 100644
--- a/gcc/c-family/c-omp.cc
+++ b/gcc/c-family/c-omp.cc
@@ -757,7 +757,7 @@ c_finish_omp_depobj (location_t loc, tree depobj,
 	      t = build2 (COMPOUND_EXPR, TREE_TYPE (t1), TREE_OPERAND (t, 0),
 			  t1);
 	    }
-	  else
+	  else if (t != null_pointer_node)
 	    t = build_fold_addr_expr (t);
 	  break;
 	default:
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index d431d5fb4c1..51a07252c7b 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -165,6 +165,14 @@ c_parse_init (void)
       C_SET_RID_CODE (id, RID_FIRST_INT_N + i);
       C_IS_RESERVED_WORD (id) = 1;
     }
+
+  if (flag_openmp)
+    {
+      id = get_identifier ("omp_all_memory");
+      C_SET_RID_CODE (id, RID_OMP_ALL_MEMORY);
+      C_IS_RESERVED_WORD (id) = 1;
+      ridpointers [RID_OMP_ALL_MEMORY] = id;
+    }
 }
 \f
 /* A parser structure recording information about the state and
@@ -10202,6 +10210,13 @@ c_parser_postfix_expression (c_parser *parser)
 	case RID_GENERIC:
 	  expr = c_parser_generic_selection (parser);
 	  break;
+	case RID_OMP_ALL_MEMORY:
+	  gcc_assert (flag_openmp);
+	  c_parser_consume_token (parser);
+	  error_at (loc, "%<omp_all_memory%> may only be used in OpenMP "
+			 "%<depend%> clause");
+	  expr.set_error ();
+	  break;
 	default:
 	  c_parser_error (parser, "expected expression");
 	  expr.set_error ();
@@ -13025,7 +13040,19 @@ c_parser_omp_variable_list (c_parser *parser,
 	  if (c_parser_next_token_is_not (parser, CPP_NAME)
 	      || c_parser_peek_token (parser)->id_kind != C_ID_ID)
 	    {
-	      struct c_expr expr = c_parser_expr_no_commas (parser, NULL);
+	      struct c_expr expr;
+	      if (kind == OMP_CLAUSE_DEPEND
+		  && c_parser_next_token_is_keyword (parser,
+						     RID_OMP_ALL_MEMORY)
+		  && (c_parser_peek_2nd_token (parser)->type == CPP_COMMA
+		      || (c_parser_peek_2nd_token (parser)->type
+			  == CPP_CLOSE_PAREN)))
+		{
+		  expr.value = ridpointers[RID_OMP_ALL_MEMORY];
+		  c_parser_consume_token (parser);
+		}
+	      else
+		expr = c_parser_expr_no_commas (parser, NULL);
 	      if (expr.value != error_mark_node)
 		{
 		  tree u = build_omp_clause (clause_loc, kind);
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index e130196a3a7..bcfe08b82bc 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -14832,6 +14832,18 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 	    }
 	  if (t == error_mark_node)
 	    remove = true;
+	  else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND
+		   && t == ridpointers[RID_OMP_ALL_MEMORY])
+	    {
+	      if (OMP_CLAUSE_DEPEND_KIND (c) != OMP_CLAUSE_DEPEND_OUT
+		  && OMP_CLAUSE_DEPEND_KIND (c) != OMP_CLAUSE_DEPEND_INOUT)
+		{
+		  error_at (OMP_CLAUSE_LOCATION (c),
+			    "%<omp_all_memory%> used with %<depend%> kind "
+			    "other than %<out%> or %<inout%>");
+		  remove = true;
+		}
+	    }
 	  else if (!lvalue_p (t))
 	    {
 	      error_at (OMP_CLAUSE_LOCATION (c),
@@ -14873,24 +14885,32 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 	    }
 	  if (!remove)
 	    {
-	      tree addr = build_unary_op (OMP_CLAUSE_LOCATION (c), ADDR_EXPR,
-					  t, false);
-	      if (addr == error_mark_node)
-		remove = true;
+	      if (t == ridpointers[RID_OMP_ALL_MEMORY])
+		t = null_pointer_node;
 	      else
 		{
+		  tree addr = build_unary_op (OMP_CLAUSE_LOCATION (c),
+					      ADDR_EXPR, t, false);
+		  if (addr == error_mark_node)
+		    {
+		      remove = true;
+		      break;
+		    }
 		  t = build_indirect_ref (OMP_CLAUSE_LOCATION (c), addr,
 					  RO_UNARY_STAR);
 		  if (t == error_mark_node)
-		    remove = true;
-		  else if (TREE_CODE (OMP_CLAUSE_DECL (c)) == TREE_LIST
-			   && TREE_PURPOSE (OMP_CLAUSE_DECL (c))
-			   && (TREE_CODE (TREE_PURPOSE (OMP_CLAUSE_DECL (c)))
-			       == TREE_VEC))
-		    TREE_VALUE (OMP_CLAUSE_DECL (c)) = t;
-		  else
-		    OMP_CLAUSE_DECL (c) = t;
+		    {
+		      remove = true;
+		      break;
+		    }
 		}
+	      if (TREE_CODE (OMP_CLAUSE_DECL (c)) == TREE_LIST
+		  && TREE_PURPOSE (OMP_CLAUSE_DECL (c))
+		  && (TREE_CODE (TREE_PURPOSE (OMP_CLAUSE_DECL (c)))
+		      == TREE_VEC))
+		TREE_VALUE (OMP_CLAUSE_DECL (c)) = t;
+	      else
+		OMP_CLAUSE_DECL (c) = t;
 	    }
 	  break;
 
diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
index 784debcd705..0b121a91e1c 100644
--- a/gcc/cp/lex.cc
+++ b/gcc/cp/lex.cc
@@ -273,6 +273,14 @@ init_reswords (void)
       C_SET_RID_CODE (id, RID_FIRST_INT_N + i);
       set_identifier_kind (id, cik_keyword);
     }
+
+  if (flag_openmp)
+    {
+      id = get_identifier ("omp_all_memory");
+      C_SET_RID_CODE (id, RID_OMP_ALL_MEMORY);
+      set_identifier_kind (id, cik_keyword);
+      ridpointers [RID_OMP_ALL_MEMORY] = id;
+    }
 }
 
 static void
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index d09d5b7c8b7..84f379c7bff 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -5876,6 +5876,14 @@ cp_parser_primary_expression (cp_parser *parser,
 	case RID_AT_SELECTOR:
 	  return cp_parser_objc_expression (parser);
 
+	case RID_OMP_ALL_MEMORY:
+	  gcc_assert (flag_openmp);
+	  cp_lexer_consume_token (parser->lexer);
+	  error_at (token->location,
+		    "%<omp_all_memory%> may only be used in OpenMP "
+		    "%<depend%> clause");
+	  return error_mark_node;
+
 	case RID_TEMPLATE:
 	  if (parser->in_function_body
 	      && (cp_lexer_peek_nth_token (parser->lexer, 2)->type
@@ -36735,6 +36743,15 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
 	  decl = cp_parser_primary_expression (parser, false, false, false,
 					       &idk);
 	}
+      else if (kind == OMP_CLAUSE_DEPEND
+	       && cp_parser_is_keyword (token, RID_OMP_ALL_MEMORY)
+	       && (cp_lexer_nth_token_is (parser->lexer, 2, CPP_COMMA)
+		   || cp_lexer_nth_token_is (parser->lexer, 2,
+					     CPP_CLOSE_PAREN)))
+	{
+	  decl = ridpointers[RID_OMP_ALL_MEMORY];
+	  cp_lexer_consume_token (parser->lexer);
+	}
       else
 	{
 	  name = cp_parser_id_expression (parser, /*template_p=*/false,
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 2c7c5f8bb5d..06b4a7d197a 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -17601,8 +17601,8 @@ static tree
 tsubst_omp_clause_decl (tree decl, tree args, tsubst_flags_t complain,
 			tree in_decl, tree *iterator_cache)
 {
-  if (decl == NULL_TREE)
-    return NULL_TREE;
+  if (decl == NULL_TREE || decl == ridpointers[RID_OMP_ALL_MEMORY])
+    return decl;
 
   /* Handle OpenMP iterators.  */
   if (TREE_CODE (decl) == TREE_LIST
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 10478d1afeb..61f49be32ff 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -7815,6 +7815,20 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 	    }
 	  if (t == error_mark_node)
 	    remove = true;
+	  else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND
+		   && t == ridpointers[RID_OMP_ALL_MEMORY])
+	    {
+	      if (OMP_CLAUSE_DEPEND_KIND (c) != OMP_CLAUSE_DEPEND_OUT
+		  && OMP_CLAUSE_DEPEND_KIND (c) != OMP_CLAUSE_DEPEND_INOUT)
+		{
+		  error_at (OMP_CLAUSE_LOCATION (c),
+			    "%<omp_all_memory%> used with %<depend%> kind "
+			    "other than %<out%> or %<inout%>");
+		  remove = true;
+		}
+	      if (processing_template_decl)
+		break;
+	    }
 	  else if (processing_template_decl && TREE_CODE (t) != OVERLOAD)
 	    break;
 	  else if (!lvalue_p (t))
@@ -7867,24 +7881,32 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 	    }
 	  if (!remove)
 	    {
-	      tree addr = cp_build_addr_expr (t, tf_warning_or_error);
-	      if (addr == error_mark_node)
-		remove = true;
+	      if (t == ridpointers[RID_OMP_ALL_MEMORY])
+		t = null_pointer_node;
 	      else
 		{
+		  tree addr = cp_build_addr_expr (t, tf_warning_or_error);
+		  if (addr == error_mark_node)
+		    {
+		      remove = true;
+		      break;
+		    }
 		  t = cp_build_indirect_ref (OMP_CLAUSE_LOCATION (c),
 					     addr, RO_UNARY_STAR,
 					     tf_warning_or_error);
 		  if (t == error_mark_node)
-		    remove = true;
-		  else if (TREE_CODE (OMP_CLAUSE_DECL (c)) == TREE_LIST
-			   && TREE_PURPOSE (OMP_CLAUSE_DECL (c))
-			   && (TREE_CODE (TREE_PURPOSE (OMP_CLAUSE_DECL (c)))
-			       == TREE_VEC))
-		    TREE_VALUE (OMP_CLAUSE_DECL (c)) = t;
-		  else
-		    OMP_CLAUSE_DECL (c) = t;
+		    {
+		      remove = true;
+		      break;
+		    }
 		}
+	      if (TREE_CODE (OMP_CLAUSE_DECL (c)) == TREE_LIST
+		  && TREE_PURPOSE (OMP_CLAUSE_DECL (c))
+		  && (TREE_CODE (TREE_PURPOSE (OMP_CLAUSE_DECL (c)))
+		      == TREE_VEC))
+		TREE_VALUE (OMP_CLAUSE_DECL (c)) = t;
+	      else
+		OMP_CLAUSE_DECL (c) = t;
 	    }
 	  break;
 	case OMP_CLAUSE_DETACH:
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index 822e0cfbf22..13413d019c4 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -8623,7 +8623,8 @@ gimplify_omp_depend (tree *list_p, gimple_seq *pre_p)
 	      }
 	    if (error_operand_p (TREE_VALUE (t)))
 	      return 2;
-	    TREE_VALUE (t) = build_fold_addr_expr (TREE_VALUE (t));
+	    if (TREE_VALUE (t) != null_pointer_node)
+	      TREE_VALUE (t) = build_fold_addr_expr (TREE_VALUE (t));
 	    r = build4 (ARRAY_REF, ptr_type_node, array, cnts[i],
 			NULL_TREE, NULL_TREE);
 	    tem = build2_loc (OMP_CLAUSE_LOCATION (c), MODIFY_EXPR,
@@ -8650,7 +8651,8 @@ gimplify_omp_depend (tree *list_p, gimple_seq *pre_p)
 	      }
 	    if (error_operand_p (OMP_CLAUSE_DECL (c)))
 	      return 2;
-	    OMP_CLAUSE_DECL (c) = build_fold_addr_expr (OMP_CLAUSE_DECL (c));
+	    if (OMP_CLAUSE_DECL (c) != null_pointer_node)
+	      OMP_CLAUSE_DECL (c) = build_fold_addr_expr (OMP_CLAUSE_DECL (c));
 	    if (gimplify_expr (&OMP_CLAUSE_DECL (c), pre_p, NULL,
 			       is_gimple_val, fb_rvalue) == GS_ERROR)
 	      return 2;
@@ -10346,12 +10348,15 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
 	      remove = true;
 	      break;
 	    }
-	  OMP_CLAUSE_DECL (c) = build_fold_addr_expr (OMP_CLAUSE_DECL (c));
-	  if (gimplify_expr (&OMP_CLAUSE_DECL (c), pre_p, NULL,
-			     is_gimple_val, fb_rvalue) == GS_ERROR)
+	  if (OMP_CLAUSE_DECL (c) != null_pointer_node)
 	    {
-	      remove = true;
-	      break;
+	      OMP_CLAUSE_DECL (c) = build_fold_addr_expr (OMP_CLAUSE_DECL (c));
+	      if (gimplify_expr (&OMP_CLAUSE_DECL (c), pre_p, NULL,
+				 is_gimple_val, fb_rvalue) == GS_ERROR)
+		{
+		  remove = true;
+		  break;
+		}
 	    }
 	  if (code == OMP_TASK)
 	    ctx->has_depend = true;
diff --git a/gcc/testsuite/c-c++-common/gomp/all-memory-1.c b/gcc/testsuite/c-c++-common/gomp/all-memory-1.c
new file mode 100644
index 00000000000..5d63e0d0939
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/all-memory-1.c
@@ -0,0 +1,52 @@
+int omp_all_memory;			/* { dg-error "expected" } */
+
+void
+foo (void)
+{
+  int p = (&omp_all_memory)[0];		/* { dg-error "'omp_all_memory' may only be used in OpenMP 'depend' clause" } */
+}
+
+void
+bar (void)
+{
+  int *omp_all_memory;			/* { dg-error "expected" } */
+}
+
+void
+baz (void)
+{
+  struct omp_all_memory { int a; };	/* { dg-error "expected" } */
+}
+
+void
+qux (void)
+{
+  union omp_all_memory { int a; };	/* { dg-error "expected" } */
+}
+
+void
+corge (void)
+{
+  enum omp_all_memory { OAM; };		/* { dg-error "expected" } */
+}
+
+void
+garply (void)
+{
+  enum E { omp_all_memory }; }		/* { dg-error "expected" } */
+
+void
+boo (void)
+{
+  int x, y;
+  #pragma omp task private (omp_all_memory)			/* { dg-error "expected" } */
+  ;
+  #pragma omp task depend(inout: *&omp_all_memory)		/* { dg-error "'omp_all_memory' may only be used in OpenMP 'depend' clause" } */
+  ;
+  #pragma omp task depend(inout: omp_all_memory[0])		/* { dg-error "'omp_all_memory' may only be used in OpenMP 'depend' clause" } */
+  ;
+  #pragma omp task depend(in: omp_all_memory)			/* { dg-error "'omp_all_memory' used with 'depend' kind other than 'out' or 'inout'" } */
+  ;
+  #pragma omp task depend(mutexinoutset: omp_all_memory)	/* { dg-error "'omp_all_memory' used with 'depend' kind other than 'out' or 'inout'" } */
+  ;
+}
diff --git a/gcc/testsuite/c-c++-common/gomp/all-memory-2.c b/gcc/testsuite/c-c++-common/gomp/all-memory-2.c
new file mode 100644
index 00000000000..6f5d31be29c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/all-memory-2.c
@@ -0,0 +1,55 @@
+/* { dg-options "-fno-openmp" } */
+
+int omp_all_memory;			/* { dg-bogus "expected" } */
+
+void
+foo (void)
+{
+  int p = (&omp_all_memory)[0];		/* { dg-bogus "'omp_all_memory' may only be used in OpenMP 'depend' clause" } */
+}
+
+void
+bar (void)
+{
+  int *omp_all_memory;			/* { dg-bogus "expected" } */
+}
+
+void
+baz (void)
+{
+  struct omp_all_memory { int a; };	/* { dg-bogus "expected" } */
+}
+
+void
+qux (void)
+{
+  union omp_all_memory { int a; };	/* { dg-bogus "expected" } */
+}
+
+void
+corge (void)
+{
+  enum omp_all_memory { OAM };		/* { dg-bogus "expected" } */
+}
+
+void
+garply (void)
+{
+  enum E { omp_all_memory };		/* { dg-bogus "expected" } */
+}
+
+void
+boo (void)
+{
+  int x, y;
+  #pragma omp task private (omp_all_memory)
+  ;
+  #pragma omp task depend(inout: *&omp_all_memory)
+  ;
+  #pragma omp task depend(inout: omp_all_memory[0])
+  ;
+  #pragma omp task depend(in: omp_all_memory)
+  ;
+  #pragma omp task depend(mutexinoutset: omp_all_memory)
+  ;
+}
diff --git a/gcc/testsuite/c-c++-common/gomp/all-memory-3.c b/gcc/testsuite/c-c++-common/gomp/all-memory-3.c
new file mode 100644
index 00000000000..f178b8d91f1
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/all-memory-3.c
@@ -0,0 +1,22 @@
+typedef struct __attribute__((__aligned__ (sizeof (void *)))) omp_depend_t {
+  char __omp_depend_t__[2 * sizeof (void *)];
+} omp_depend_t;
+
+omp_depend_t z;
+
+void
+foo (void)
+{
+  int x = 0, y = 0;
+  #pragma omp task depend(out: omp_all_memory)
+  ;
+  #pragma omp task depend(inout: omp_all_memory)
+  ;
+  #pragma omp task depend(out: x, omp_all_memory, y)
+  ;
+  #pragma omp task depend(inout: omp_all_memory, y)
+  ;
+  #pragma omp task depend(out: x, omp_all_memory)
+  ;
+  #pragma omp depobj (z) depend (inout: omp_all_memory)
+}
diff --git a/gcc/testsuite/g++.dg/gomp/all-memory-1.C b/gcc/testsuite/g++.dg/gomp/all-memory-1.C
new file mode 100644
index 00000000000..8f3358df8b1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/all-memory-1.C
@@ -0,0 +1,24 @@
+namespace A
+{
+  namespace omp_all_memory		// { dg-error "expected" }
+  {
+  }
+}
+
+namespace B
+{
+  template <int N>
+  void omp_all_memory () {}		// { dg-error "expected" }
+}
+
+namespace C
+{
+  template <int N>
+  struct omp_all_memory {};		// { dg-error "expected" }
+}
+
+namespace D
+{
+  template <int omp_all_memory>		// { dg-error "expected" }
+  struct S {};
+}
diff --git a/gcc/testsuite/g++.dg/gomp/all-memory-2.C b/gcc/testsuite/g++.dg/gomp/all-memory-2.C
new file mode 100644
index 00000000000..1acf3915a92
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/all-memory-2.C
@@ -0,0 +1,26 @@
+// { dg-options "-fno-openmp" }
+
+namespace A
+{
+  namespace omp_all_memory		// { dg-bogus "expected" }
+  {
+  }
+}
+
+namespace B
+{
+  template <int N>
+  void omp_all_memory () {}		// { dg-bogus "expected" }
+}
+
+namespace C
+{
+  template <int N>
+  struct omp_all_memory {};		// { dg-bogus "expected" }
+}
+
+namespace D
+{
+  template <int omp_all_memory>		// { dg-bogus "expected" }
+  struct S {};
+}
diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc
index 99af977979d..d7615aa51a8 100644
--- a/gcc/tree-pretty-print.cc
+++ b/gcc/tree-pretty-print.cc
@@ -850,7 +850,10 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags)
 	    pp_string (pp, name);
 	    pp_colon (pp);
 	  }
-	dump_generic_node (pp, t, spc, flags, false);
+	if (t == null_pointer_node)
+	  pp_string (pp, "omp_all_memory");
+	else
+	  dump_generic_node (pp, t, spc, flags, false);
 	pp_right_paren (pp);
       }
       break;
diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h
index b9e03919993..295d10fd0c3 100644
--- a/libgomp/libgomp.h
+++ b/libgomp/libgomp.h
@@ -574,6 +574,8 @@ struct gomp_task
   struct gomp_dependers_vec *dependers;
   struct htab *depend_hash;
   struct gomp_taskwait *taskwait;
+  /* Last depend({,in}out:omp_all_memory) child if any.  */
+  struct gomp_task *depend_all_memory;
   /* Number of items in DEPEND.  */
   size_t depend_count;
   /* Number of tasks this task depends on.  Once this counter reaches
diff --git a/libgomp/task.c b/libgomp/task.c
index 828348c4cf4..db4a6f71fb7 100644
--- a/libgomp/task.c
+++ b/libgomp/task.c
@@ -80,6 +80,7 @@ gomp_init_task (struct gomp_task *task, struct gomp_task *parent_task,
   task->dependers = NULL;
   task->depend_hash = NULL;
   task->taskwait = NULL;
+  task->depend_all_memory = NULL;
   task->depend_count = 0;
   task->completion_sem = NULL;
   task->deferred_p = false;
@@ -171,6 +172,7 @@ gomp_task_handle_depend (struct gomp_task *task, struct gomp_task *parent,
   size_t ndepend = (uintptr_t) depend[0];
   size_t i;
   hash_entry_type ent;
+  bool all_memory = false;
 
   if (ndepend)
     {
@@ -181,6 +183,7 @@ gomp_task_handle_depend (struct gomp_task *task, struct gomp_task *parent,
 	{
 	  task->depend[i].addr = depend[2 + i];
 	  task->depend[i].is_in = i >= nout;
+	  all_memory |= i < nout && depend[2 + i] == NULL;
 	}
     }
   else
@@ -201,6 +204,8 @@ gomp_task_handle_depend (struct gomp_task *task, struct gomp_task *parent,
 	    {
 	    case GOMP_DEPEND_OUT:
 	    case GOMP_DEPEND_INOUT:
+	      all_memory |= d[0] == NULL;
+	      break;
 	    case GOMP_DEPEND_MUTEXINOUTSET:
 	      break;
 	    case GOMP_DEPEND_IN:
@@ -226,8 +231,126 @@ gomp_task_handle_depend (struct gomp_task *task, struct gomp_task *parent,
 	  task->depend[n++].is_in = 1;
 	}
     }
-  task->depend_count = ndepend;
   task->num_dependees = 0;
+  if (__builtin_expect (parent->depend_all_memory && ndepend, false))
+    {
+      struct gomp_task *tsk = parent->depend_all_memory;
+      if (tsk->dependers == NULL)
+	{
+	  tsk->dependers
+	    = gomp_malloc (sizeof (struct gomp_dependers_vec)
+			   + 6 * sizeof (struct gomp_task *));
+	  tsk->dependers->n_elem = 1;
+	  tsk->dependers->allocated = 6;
+	  tsk->dependers->elem[0] = task;
+	}
+      else
+	{
+	  if (tsk->dependers->n_elem == tsk->dependers->allocated)
+	    {
+	      tsk->dependers->allocated
+		= tsk->dependers->allocated * 2 + 2;
+	      tsk->dependers
+		= gomp_realloc (tsk->dependers,
+				sizeof (struct gomp_dependers_vec)
+				+ (tsk->dependers->allocated
+				   * sizeof (struct gomp_task *)));
+	    }
+	  tsk->dependers->elem[tsk->dependers->n_elem++] = task;
+	}
+      task->num_dependees++;
+    }
+  if (__builtin_expect (all_memory, false))
+    {
+      /* A task with depend(inout: omp_all_memory) depends on all previous
+	 sibling tasks which have any dependencies and all later sibling
+	 tasks which have any dependencies depend on it.  */
+      task->depend_count = 1;
+      task->depend[0].addr = NULL;
+      task->depend[0].next = NULL;
+      task->depend[0].prev = NULL;
+      task->depend[0].task = task;
+      task->depend[0].redundant = true;
+      task->depend[0].redundant_out = false;
+      if (parent->depend_hash)
+	{
+	  /* Inlined htab_traverse + htab_clear.  All newer siblings can
+	     just depend on this task.  Add dependencies on all previous
+	     sibling tasks with dependencies and make them redundant and
+	     clear the hash table.  */
+	  hash_entry_type *slot = &parent->depend_hash->entries[0];
+	  hash_entry_type *end = slot + htab_size (parent->depend_hash);
+	  for (; slot != end; ++slot)
+	    {
+	      if (*slot == HTAB_EMPTY_ENTRY)
+		continue;
+	      if (*slot != HTAB_DELETED_ENTRY)
+		{
+		  for (ent = *slot; ent; ent = ent->next)
+		    {
+		      struct gomp_task *tsk = ent->task;
+
+		      if (ent->redundant_out)
+			break;
+
+		      ent->redundant = true;
+		      if (tsk->dependers == NULL)
+			{
+			  tsk->dependers
+			    = gomp_malloc (sizeof (struct gomp_dependers_vec)
+					   + 6 * sizeof (struct gomp_task *));
+			  tsk->dependers->n_elem = 1;
+			  tsk->dependers->allocated = 6;
+			  tsk->dependers->elem[0] = task;
+			  task->num_dependees++;
+			  continue;
+			}
+		      /* We already have some other dependency on tsk from
+			 earlier depend clause.  */
+		      else if (tsk->dependers->n_elem
+			       && (tsk->dependers->elem[tsk->dependers->n_elem
+							- 1] == task))
+			continue;
+		      else if (tsk->dependers->n_elem
+			       == tsk->dependers->allocated)
+			{
+			  tsk->dependers->allocated
+			    = tsk->dependers->allocated * 2 + 2;
+			  tsk->dependers
+			    = gomp_realloc (tsk->dependers,
+					    sizeof (struct gomp_dependers_vec)
+					    + (tsk->dependers->allocated
+					       * sizeof (struct gomp_task *)));
+			}
+		      tsk->dependers->elem[tsk->dependers->n_elem++] = task;
+		      task->num_dependees++;
+		    }
+		  while (ent)
+		    {
+		      ent->redundant = true;
+		      ent = ent->next;
+		    }
+		}
+	      *slot = HTAB_EMPTY_ENTRY;
+	    }
+	  if (htab_size (parent->depend_hash) <= 32)
+	    {
+	      parent->depend_hash->n_elements = 0;
+	      parent->depend_hash->n_deleted = 0;
+	    }
+	  else
+	    {
+	      /* Shrink the hash table if it would be too large.
+		 We don't want to walk e.g. megabytes of empty hash
+		 table for every depend(inout: omp_all_memory).  */
+	      free (parent->depend_hash);
+	      parent->depend_hash = htab_create (12);
+	    }
+	}
+      parent->depend_all_memory = task;
+      return;
+    }
+  task->depend_count = ndepend;
   if (parent->depend_hash == NULL)
     parent->depend_hash = htab_create (2 * ndepend > 12 ? 2 * ndepend : 12);
   for (i = 0; i < ndepend; i++)
@@ -1175,6 +1298,8 @@ gomp_task_run_post_handle_depend_hash (struct gomp_task *child_task)
   struct gomp_task *parent = child_task->parent;
   size_t i;
 
+  if (parent->depend_all_memory == child_task)
+    parent->depend_all_memory = NULL;
   for (i = 0; i < child_task->depend_count; i++)
     if (!child_task->depend[i].redundant)
       {
@@ -1738,6 +1863,17 @@ gomp_task_maybe_wait_for_dependencies (void **depend)
       n = 5;
     }
   gomp_mutex_lock (&team->task_lock);
+  if (__builtin_expect (task->depend_all_memory && ndepend, false))
+    {
+      struct gomp_task *tsk = task->depend_all_memory;
+      if (!tsk->parent_depends_on)
+	{
+	  tsk->parent_depends_on = true;
+	  ++num_awaited;
+	  if (tsk->num_dependees == 0 && tsk->kind == GOMP_TASK_WAITING)
+	    priority_queue_upgrade_task (tsk, task);
+	}
+    }
   for (i = 0; i < ndepend; i++)
     {
       elem.addr = depend[i + n];
@@ -1760,6 +1896,36 @@ gomp_task_maybe_wait_for_dependencies (void **depend)
 	    }
 	  elem.addr = d[0];
 	}
+      if (__builtin_expect (elem.addr == NULL && !elem.is_in, false))
+	{
+	  size_t size = htab_size (task->depend_hash);
+	  if (htab_elements (task->depend_hash) * 8 < size && size > 32)
+	    htab_expand (task->depend_hash);
+
+	  /* depend(inout: omp_all_memory) - depend on all previous
+	     sibling tasks that do have dependencies.  Inlined
+	     htab_traverse.  */
+	  hash_entry_type *slot = &task->depend_hash->entries[0];
+	  hash_entry_type *end = slot + htab_size (task->depend_hash);
+	  for (; slot != end; ++slot)
+	    {
+	      if (*slot == HTAB_EMPTY_ENTRY || *slot == HTAB_DELETED_ENTRY)
+		continue;
+	      for (ent = *slot; ent; ent = ent->next)
+		{
+		  struct gomp_task *tsk = ent->task;
+		  if (!tsk->parent_depends_on)
+		    {
+		      tsk->parent_depends_on = true;
+		      ++num_awaited;
+		      if (tsk->num_dependees == 0
+			  && tsk->kind == GOMP_TASK_WAITING)
+			priority_queue_upgrade_task (tsk, task);
+		    }
+		}
+	    }
+	  break;
+	}
       ent = htab_find (task->depend_hash, &elem);
       for (; ent; ent = ent->next)
 	if (elem.is_in && ent->is_in)
diff --git a/libgomp/testsuite/libgomp.c-c++-common/depend-1.c b/libgomp/testsuite/libgomp.c-c++-common/depend-1.c
new file mode 100644
index 00000000000..3376b99b18c
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/depend-1.c
@@ -0,0 +1,110 @@
+#include <stdlib.h>
+#include <unistd.h>
+
+void
+test (int ifval)
+{
+  int a[8], b[8], i;
+  for (i = 0; i < 8; i++)
+    {
+      a[i] = i;
+      b[i] = 2 * i;
+    }
+  #pragma omp parallel
+  #pragma omp single
+  {
+    #pragma omp task shared(a) depend(in: a[0])
+    {
+      usleep (5000);
+      a[0] = 42;
+    }
+    #pragma omp task shared(a) depend(out: a[1])
+    {
+      usleep (5000);
+      a[1] = 43;
+    }
+    #pragma omp task shared(a) depend(inout: a[2])
+    {
+      usleep (5000);
+      a[2] = 44;
+    }
+    #pragma omp task shared(a) depend(mutexinoutset: a[3])
+    {
+      usleep (5000);
+      a[3] = 45;
+    }
+    #pragma omp task shared(a)
+    {
+      usleep (15000);
+      a[4] = 46;
+    }
+    #pragma omp task shared(b) depend(in: b[0])
+    {
+      usleep (5000);
+      b[0] = 47;
+    }
+    #pragma omp task shared(b) depend(in: b[4])
+    {
+      usleep (5000);
+      b[4] = 48;
+    }
+    /* None of the above tasks depend on each other.
+       The following task depends on all but the a[4] = 46; one.  */
+    #pragma omp task shared(a, b) depend(out: omp_all_memory) private(i) if(ifval)
+    {
+      if (a[0] != 42 || a[1] != 43 || a[2] != 44 || a[3] != 45
+	  || a[5] != 5 || a[6] != 6 || a[7] != 7
+	  || b[0] != 47 || b[1] != 2 || b[2] != 4 || b[3] != 6
+	  || b[4] != 48 || b[5] != 10 || b[6] != 12 || b[7] != 14)
+	abort ();
+      for (i = 0; i < 8; ++i)
+	if (i != 4)
+	  a[i] = 3 * i + 7;
+      for (i = 0; i < 8; ++i)
+	b[i] = 4 * i - 7;
+    }
+    /* The following task depends on both b[0] = 47; and
+       above omp_all_memory tasks, but as the latter depends on
+       the former, effectively it is dependent just on the omp_all_memory
+       task.  */
+    #pragma omp task shared(b) depend(inout: b[0])
+    {
+      usleep (5000);
+      b[0] = 49;
+    }
+    /* The following task depends on all the above except a[4] = 46; one,
+       but it can be reduced to dependency on the above omp_all_memory
+       one and b[0] = 49; one.  */
+    #pragma omp task shared(a, b) depend(inout: b[7], omp_all_memory, b[6]) \
+		     private(i) if(ifval)
+    {
+      for (i = 0; i < 8; ++i)
+	if (i != 4)
+	  {
+	    if (a[i] != 3 * i + 7)
+	      abort ();
+	    a[i] = 5 * i + 50;
+	  }
+      if (b[0] != 49)
+	abort ();
+      b[0] = 6 * i + 57;
+      for (i = 1; i < 8; ++i)
+	{
+	  if (b[i] != 4 * i - 7) 
+	    abort ();
+	  b[i] = 6 * i + 57;
+	}
+    }
+    #pragma omp taskwait
+    if (a[4] != 46)
+      abort ();
+  }
+}
+
+int
+main ()
+{
+  test (1);
+  test (0);
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/depend-2.c b/libgomp/testsuite/libgomp.c-c++-common/depend-2.c
new file mode 100644
index 00000000000..d7b533555c4
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/depend-2.c
@@ -0,0 +1,116 @@
+#include <omp.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+void
+test (int ifval)
+{
+  int a[8], b[8], i;
+  omp_depend_t d1, d2;
+  #pragma omp depobj (d1) depend(inout: omp_all_memory) 
+  #pragma omp depobj (d2) depend(out: omp_all_memory)
+  for (i = 0; i < 8; i++)
+    {
+      a[i] = i;
+      b[i] = 2 * i;
+    }
+  #pragma omp parallel
+  #pragma omp single
+  {
+    #pragma omp task shared(a) depend(in: a[0])
+    {
+      usleep (5000);
+      a[0] = 42;
+    }
+    #pragma omp task shared(a) depend(out: a[1])
+    {
+      usleep (5000);
+      a[1] = 43;
+    }
+    #pragma omp task shared(a) depend(inout: a[2])
+    {
+      usleep (5000);
+      a[2] = 44;
+    }
+    #pragma omp task shared(a) depend(mutexinoutset: a[3])
+    {
+      usleep (5000);
+      a[3] = 45;
+    }
+    #pragma omp task shared(a)
+    {
+      usleep (15000);
+      a[4] = 46;
+    }
+    #pragma omp task shared(b) depend(in: b[0])
+    {
+      usleep (5000);
+      b[0] = 47;
+    }
+    #pragma omp task shared(b) depend(in: b[4])
+    {
+      usleep (5000);
+      b[4] = 48;
+    }
+    /* None of the above tasks depend on each other.
+       The following task depends on all but the a[4] = 46; one.  */
+    #pragma omp task shared(a, b) depend(depobj: d1) private(i) if(ifval)
+    {
+      if (a[0] != 42 || a[1] != 43 || a[2] != 44 || a[3] != 45
+	  || a[5] != 5 || a[6] != 6 || a[7] != 7
+	  || b[0] != 47 || b[1] != 2 || b[2] != 4 || b[3] != 6
+	  || b[4] != 48 || b[5] != 10 || b[6] != 12 || b[7] != 14)
+	abort ();
+      for (i = 0; i < 8; ++i)
+	if (i != 4)
+	  a[i] = 3 * i + 7;
+      for (i = 0; i < 8; ++i)
+	b[i] = 4 * i - 7;
+    }
+    /* The following task depends on both b[0] = 47; and
+       above omp_all_memory tasks, but as the latter depends on
+       the former, effectively it is dependent just on the omp_all_memory
+       task.  */
+    #pragma omp task shared(b) depend(inout: b[0])
+    {
+      usleep (5000);
+      b[0] = 49;
+    }
+    /* The following task depends on all the above except a[4] = 46; one,
+       but it can be reduced to dependency on the above omp_all_memory
+       one and b[0] = 49; one.  */
+    #pragma omp task shared(a, b) depend(inout: b[6]) depend(depobj: d2) \
+		     depend(out: b[7]) private(i) if(ifval)
+    {
+      for (i = 0; i < 8; ++i)
+	if (i != 4)
+	  {
+	    if (a[i] != 3 * i + 7)
+	      abort ();
+	    a[i] = 5 * i + 50;
+	  }
+      if (b[0] != 49)
+	abort ();
+      b[0] = 6 * i + 57;
+      for (i = 1; i < 8; ++i)
+	{
+	  if (b[i] != 4 * i - 7) 
+	    abort ();
+	  b[i] = 6 * i + 57;
+	}
+    }
+    #pragma omp taskwait
+    if (a[4] != 46)
+      abort ();
+  }
+  #pragma omp depobj (d2) destroy
+  #pragma omp depobj (d1) destroy
+}
+
+int
+main ()
+{
+  test (1);
+  test (0);
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/depend-3.c b/libgomp/testsuite/libgomp.c-c++-common/depend-3.c
new file mode 100644
index 00000000000..052e77c81e1
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/depend-3.c
@@ -0,0 +1,103 @@
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+main ()
+{
+  int a[8], b[8], i;
+  for (i = 0; i < 8; i++)
+    {
+      a[i] = i;
+      b[i] = 2 * i;
+    }
+  #pragma omp parallel
+  #pragma omp single
+  {
+    #pragma omp task shared(a) depend(in: a[0])
+    {
+      usleep (5000);
+      a[0] = 42;
+    }
+    #pragma omp task shared(a) depend(out: a[1])
+    {
+      usleep (5000);
+      a[1] = 43;
+    }
+    #pragma omp task shared(a) depend(inout: a[2])
+    {
+      usleep (5000);
+      a[2] = 44;
+    }
+    #pragma omp task shared(a) depend(mutexinoutset: a[3])
+    {
+      usleep (5000);
+      a[3] = 45;
+    }
+    #pragma omp task shared(a)
+    {
+      usleep (15000);
+      a[4] = 46;
+    }
+    #pragma omp task shared(b) depend(in: b[0])
+    {
+      usleep (5000);
+      b[0] = 47;
+    }
+    #pragma omp task shared(b) depend(in: b[4])
+    {
+      usleep (5000);
+      b[4] = 48;
+    }
+    /* None of the above tasks depend on each other.
+       The following task depends on all but the a[4] = 46; one.  */
+    #pragma omp task shared(a, b) depend(iterator (j=0:7), inout: omp_all_memory) private(i)
+    {
+      if (a[0] != 42 || a[1] != 43 || a[2] != 44 || a[3] != 45
+	  || a[5] != 5 || a[6] != 6 || a[7] != 7
+	  || b[0] != 47 || b[1] != 2 || b[2] != 4 || b[3] != 6
+	  || b[4] != 48 || b[5] != 10 || b[6] != 12 || b[7] != 14)
+	abort ();
+      for (i = 0; i < 8; ++i)
+	if (i != 4)
+	  a[i] = 3 * i + 7;
+      for (i = 0; i < 8; ++i)
+	b[i] = 4 * i - 7;
+    }
+    /* The following task depends on both b[0] = 47; and
+       above omp_all_memory tasks, but as the latter depends on
+       the former, effectively it is dependent just on the omp_all_memory
+       task.  */
+    #pragma omp task shared(b) depend(inout: b[0])
+    {
+      usleep (5000);
+      b[0] = 49;
+    }
+    /* The following task depends on all the above except a[4] = 46; one,
+       but it can be reduced to dependency on the above omp_all_memory
+       one and b[0] = 49; one.  */
+    #pragma omp task shared(a, b) depend(inout: b[7]) depend(iterator(j=4:5), out: omp_all_memory) \
+		     depend(inout: b[6]) private(i)
+    {
+      for (i = 0; i < 8; ++i)
+	if (i != 4)
+	  {
+	    if (a[i] != 3 * i + 7)
+	      abort ();
+	    a[i] = 5 * i + 50;
+	  }
+      if (b[0] != 49)
+	abort ();
+      b[0] = 6 * i + 57;
+      for (i = 1; i < 8; ++i)
+	{
+	  if (b[i] != 4 * i - 7) 
+	    abort ();
+	  b[i] = 6 * i + 57;
+	}
+    }
+    #pragma omp taskwait
+    if (a[4] != 46)
+      abort ();
+  }
+  return 0;
+}


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

only message in thread, other threads:[~2022-05-12  6:39 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-12  6:39 [gcc r13-337] openmp: Add omp_all_memory support (C/C++ only so far) Jakub Jelinek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).