]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
openmp: Add omp_all_memory support (C/C++ only so far)
authorJakub Jelinek <jakub@redhat.com>
Thu, 12 May 2022 06:31:20 +0000 (08:31 +0200)
committerKwok Cheung Yeung <kcy@codesourcery.com>
Tue, 28 Jun 2022 20:55:29 +0000 (13:55 -0700)
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.

(cherry picked from commit 7f78783dbedca0183d193e475262ca3c489fd365)

26 files changed:
gcc/ChangeLog.omp
gcc/c-family/ChangeLog.omp
gcc/c-family/c-common.h
gcc/c-family/c-omp.cc
gcc/c/ChangeLog.omp
gcc/c/c-parser.cc
gcc/c/c-typeck.cc
gcc/cp/ChangeLog.omp
gcc/cp/lex.cc
gcc/cp/parser.cc
gcc/cp/pt.cc
gcc/cp/semantics.cc
gcc/gimplify.cc
gcc/testsuite/ChangeLog.omp
gcc/testsuite/c-c++-common/gomp/all-memory-1.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/gomp/all-memory-2.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/gomp/all-memory-3.c [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/all-memory-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/all-memory-2.C [new file with mode: 0644]
gcc/tree-pretty-print.cc
libgomp/ChangeLog.omp
libgomp/libgomp.h
libgomp/task.c
libgomp/testsuite/libgomp.c-c++-common/depend-1.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c-c++-common/depend-2.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c-c++-common/depend-3.c [new file with mode: 0644]

index de95d4136cd9897fe7fddbf8a08bdb1bbc2eecca..eba48717ee8d987adbf766c1b870a2000db41ec7 100644 (file)
@@ -1,3 +1,14 @@
+2022-05-12  Jakub Jelinek  <jakub@redhat.com>
+
+       Backport from mainline:
+       2022-05-12  Jakub Jelinek  <jakub@redhat.com>
+
+       * 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.
+
 2022-04-06  Thomas Schwinge  <thomas@codesourcery.com>
 
        Backport from mainline:
index 5a928189703a861d6d7c52a9c130eb82745ccb9d..84e73af682467187a491eff29154b42ab7988d2f 100644 (file)
@@ -1,3 +1,12 @@
+2022-05-12  Jakub Jelinek  <jakub@redhat.com>
+
+       Backport from mainline:
+       2022-05-12  Jakub Jelinek  <jakub@redhat.com>
+
+       * 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.
+
 2022-06-17  Chung-Lin Tang  <cltang@codesourcery.com>
 
        Backport from mainline:
index 85c3d5d55ddf03357c0f2424e65405b9919aa74d..9109a76cd75f80a21fd18f8aad1ff2fda9e377d6 100644 (file)
@@ -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
index 377465f59263170f5b11098c783c4389ed00385c..ddcd52f06e7d7697364c1a2da5b5f276259bfb2c 100644 (file)
@@ -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:
index c3cfb6d5dc2ac07d97b7c9e609624aa7a8e10748..219087795965e8535ccb267cb81d8b5b95dec880 100644 (file)
@@ -1,3 +1,18 @@
+2022-05-12  Jakub Jelinek  <jakub@redhat.com>
+
+       Backport from mainline:
+       2022-05-12  Jakub Jelinek  <jakub@redhat.com>
+
+       * 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.
+
 2022-06-17  Chung-Lin Tang  <cltang@codesourcery.com>
 
        Backport from mainline:
index 1e89ca9fdf22daf7c7db026f681b5fb8cbbb37bd..363b80ebfeb67d36d41751f41d9eb86ea8aa058c 100644 (file)
@@ -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
@@ -10223,6 +10231,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 ();
@@ -13053,7 +13068,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);
index a85e438ffcebc79177e53d8efbd7a3f8ae18b230..bfbaf0feadc2abb187f037f8c5d011ebbabdcd58 100644 (file)
@@ -15026,6 +15026,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),
@@ -15067,24 +15079,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;
 
index 79e6bfdceff35ebb1a06f123c8d6c386dfdff62a..01ffe06efcf0c05b361d8fcfcc6c46bb80df1fcf 100644 (file)
@@ -1,3 +1,19 @@
+2022-05-12  Jakub Jelinek  <jakub@redhat.com>
+
+       Backport from mainline:
+       2022-05-12  Jakub Jelinek  <jakub@redhat.com>
+
+       * 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.
+
 2022-06-17  Chung-Lin Tang  <cltang@codesourcery.com>
 
        Backport from mainline:
index 739f0890e01a646f46b47b53d77bafc64376c9ac..99498659ed627482a81a2148c51193296b74a07f 100644 (file)
@@ -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
index e1193406435ad3eb9e684b092f21e604c7a3a173..563bf4546eb1c11f7b311e26f84b0e7538f30a28 100644 (file)
@@ -5890,6 +5890,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
@@ -36612,6 +36620,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,
index e785c5db14208257f572159da5330e89f5ccc7aa..2f1a52e2dc36000f927a92ac6a6d9ee41e52f1ff 100644 (file)
@@ -17588,8 +17588,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
index 70ebf7d84139fffc9c74c01ec2673cd9f5750f49..c2f9d3bd4162f6cfca80ec5253b954165380d41e 100644 (file)
@@ -7997,6 +7997,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))
@@ -8049,24 +8063,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:
index f1df08c993600c9b1755cf01d9ce68f912eb9bae..8e8151cfc3580fed2a69854b89d2b6453053792a 100644 (file)
@@ -8655,7 +8655,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,
@@ -8682,7 +8683,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;
@@ -10821,12 +10823,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;
index 95d966fd7dc0c1cf1e3316e7a56e6c85aa260248..301085fba5d6cb0f90fb471dfb220a41916d4483 100644 (file)
@@ -1,3 +1,14 @@
+2022-05-12  Jakub Jelinek  <jakub@redhat.com>
+
+       Backport from mainline:
+       2022-05-12  Jakub Jelinek  <jakub@redhat.com>
+
+       * 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.
+
 2022-05-05  Sandra Loosemore <sandra@codesourcery.com>
 
        Backport from mainline:
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 (file)
index 0000000..5d63e0d
--- /dev/null
@@ -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 (file)
index 0000000..6f5d31b
--- /dev/null
@@ -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 (file)
index 0000000..f178b8d
--- /dev/null
@@ -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 (file)
index 0000000..8f3358d
--- /dev/null
@@ -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 (file)
index 0000000..1acf391
--- /dev/null
@@ -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 {};
+}
index d02a5a4b4ff5f5cf7f9aa372295169de56b5424a..b200be3b34d0698152eab152943125ece44bbe5f 100644 (file)
@@ -878,7 +878,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;
index 05be22348e2e1bb4abffacff8e13bce3329062bd..0d4d2d12583d1627ef971741327eeded6c37b53e 100644 (file)
@@ -1,3 +1,18 @@
+2022-05-12  Jakub Jelinek  <jakub@redhat.com>
+
+       Backport from mainline:
+       2022-05-12  Jakub Jelinek  <jakub@redhat.com>
+
+       * 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.
+
 2022-04-06  Thomas Schwinge  <thomas@codesourcery.com>
 
        Backport from mainline:
index 24470cdb6a5bb6f85723a42eca622a6076a1e6a0..a6aab1de38f5464f06921896ebff46ad502831f0 100644 (file)
@@ -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
index 828348c4cf4815a3d71e531ae1100392126bd43a..db4a6f71fb76512121192e504f52f89f7ae00b79 100644 (file)
@@ -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 (file)
index 0000000..3376b99
--- /dev/null
@@ -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 (file)
index 0000000..d7b5335
--- /dev/null
@@ -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 (file)
index 0000000..052e77c
--- /dev/null
@@ -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;
+}