diff options
-rw-r--r-- | gcc/c-family/c-common.h | 3 | ||||
-rw-r--r-- | gcc/c-family/c-omp.cc | 2 | ||||
-rw-r--r-- | gcc/c/c-parser.cc | 29 | ||||
-rw-r--r-- | gcc/c/c-typeck.cc | 44 | ||||
-rw-r--r-- | gcc/cp/lex.cc | 8 | ||||
-rw-r--r-- | gcc/cp/parser.cc | 17 | ||||
-rw-r--r-- | gcc/cp/pt.cc | 4 | ||||
-rw-r--r-- | gcc/cp/semantics.cc | 44 | ||||
-rw-r--r-- | gcc/gimplify.cc | 19 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/gomp/all-memory-1.c | 52 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/gomp/all-memory-2.c | 55 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/gomp/all-memory-3.c | 22 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/gomp/all-memory-1.C | 24 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/gomp/all-memory-2.C | 26 | ||||
-rw-r--r-- | gcc/tree-pretty-print.cc | 5 | ||||
-rw-r--r-- | libgomp/libgomp.h | 2 | ||||
-rw-r--r-- | libgomp/task.c | 168 | ||||
-rw-r--r-- | libgomp/testsuite/libgomp.c-c++-common/depend-1.c | 110 | ||||
-rw-r--r-- | libgomp/testsuite/libgomp.c-c++-common/depend-2.c | 116 | ||||
-rw-r--r-- | libgomp/testsuite/libgomp.c-c++-common/depend-3.c | 103 |
20 files changed, 817 insertions, 36 deletions
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 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; +} |