]> 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)
committerJakub Jelinek <jakub@redhat.com>
Thu, 12 May 2022 06:31:20 +0000 (08:31 +0200)
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.

20 files changed:
gcc/c-family/c-common.h
gcc/c-family/c-omp.cc
gcc/c/c-parser.cc
gcc/c/c-typeck.cc
gcc/cp/lex.cc
gcc/cp/parser.cc
gcc/cp/pt.cc
gcc/cp/semantics.cc
gcc/gimplify.cc
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/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 aa043defe9e63c4600f992030d7618d2e2912ccd..47442c95a53528161cb1f592adc1b113ed493288 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 777cdc655722d6e0ecd11a92f3cc39cbeccebb7e..987ba7d724aea62955d368e563eaa6a9883c4086 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 d431d5fb4c1782edfaa91fcf3e671fbafdbc0986..51a07252c7b94dd7e430117ac1318f5ecfdcd466 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
@@ -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);
index e130196a3a7271064b617504f0fd1a74d1e18ffa..bcfe08b82bcf157fe369bd8ffafe9aa1e4826b51 100644 (file)
@@ -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;
 
index 784debcd705402dda68c471554409ba3a8b9a67b..0b121a91e1cdeb0c04fdc0c68a21ee6f04e03bf5 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 d09d5b7c8b7434d16dc98c486f94b5e148617a90..84f379c7bff331b1501a4a33562a273a4a241d9d 100644 (file)
@@ -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,
index 2c7c5f8bb5dedc6cefd2d639eece83a4dd517a55..06b4a7d197a39632a4f0c13974c8d589bd50998f 100644 (file)
@@ -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
index 10478d1afeb68000770165d0aecaf7ff39e884c6..61f49be32ff5390210a24fa9df72e452c3b64e9b 100644 (file)
@@ -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:
index 822e0cfbf220d0914be2c94773e81474f8949f7e..13413d019c4be8c0550225f5f205dfb51fe2ff38 100644 (file)
@@ -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 (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 99af977979d5891e6e8345276af794f421ecfaac..d7615aa51a86960669f8cbecb6ab0326ddfba533 100644 (file)
@@ -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;
index b9e039199930c078804b463e047d49d950eb8e18..295d10fd0c349f5bae825962a28ab685ab358947 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;
+}