aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/c-family/c-common.h3
-rw-r--r--gcc/c-family/c-omp.cc2
-rw-r--r--gcc/c/c-parser.cc29
-rw-r--r--gcc/c/c-typeck.cc44
-rw-r--r--gcc/cp/lex.cc8
-rw-r--r--gcc/cp/parser.cc17
-rw-r--r--gcc/cp/pt.cc4
-rw-r--r--gcc/cp/semantics.cc44
-rw-r--r--gcc/gimplify.cc19
-rw-r--r--gcc/testsuite/c-c++-common/gomp/all-memory-1.c52
-rw-r--r--gcc/testsuite/c-c++-common/gomp/all-memory-2.c55
-rw-r--r--gcc/testsuite/c-c++-common/gomp/all-memory-3.c22
-rw-r--r--gcc/testsuite/g++.dg/gomp/all-memory-1.C24
-rw-r--r--gcc/testsuite/g++.dg/gomp/all-memory-2.C26
-rw-r--r--gcc/tree-pretty-print.cc5
-rw-r--r--libgomp/libgomp.h2
-rw-r--r--libgomp/task.c168
-rw-r--r--libgomp/testsuite/libgomp.c-c++-common/depend-1.c110
-rw-r--r--libgomp/testsuite/libgomp.c-c++-common/depend-2.c116
-rw-r--r--libgomp/testsuite/libgomp.c-c++-common/depend-3.c103
20 files changed, 817 insertions, 36 deletions
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index aa043de..47442c9 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 777cdc6..987ba7d 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 d431d5f..51a0725 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;
+ }
}
/* 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 e130196..bcfe08b 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 784debc..0b121a9 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 d09d5b7..84f379c 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 2c7c5f8..06b4a7d 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 10478d1..61f49be 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 822e0cf..13413d0 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 0000000..5d63e0d
--- /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 0000000..6f5d31b
--- /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 0000000..f178b8d
--- /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 0000000..8f3358d
--- /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 0000000..1acf391
--- /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 99af977..d7615aa 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 b9e0391..295d10f 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 828348c..db4a6f7 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 0000000..3376b99
--- /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 0000000..d7b5335
--- /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 0000000..052e77c
--- /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;
+}