Hi! This patch adds #pragma omp depobj support, so that the task dependencies can be built at one spot and used later on from the omp_depend_t structure that has all the necessary information (object address and dependence type) later on.
In addition this fixes some problems in the depend clause handling, e.g. handles references correctly, or e.g. C++ x ? y : z lvalues, --x lvalues etc. Mutexinoutset is also propagated to the library, which right now still handles it conservatively as inout/out. Tested on x86_64-linux, committed to gomp-5_0-branch. 2018-06-28 Jakub Jelinek <ja...@redhat.com> * tree-core.h (enum omp_clause_depend_kind): Add OMP_CLAUSE_DEPEND_UNSPECIFIED. * gimplify.c (gimplify_omp_depend): If there are any OMP_CLAUSE_DEPEND_UNSPECIFIED or OMP_CLAUSE_DEPEND_MUTEXINOUTSET depend clauses, use a new array format. * omp-low.c (lower_depend_clauses): Likewise. * tree-pretty-print.c (dump_omp_clause): Handle OMP_CLAUSE_DEPEND_UNSPECIFIED. gcc/c-family/ * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_DEPOBJ. * c-pragma.c (omp_pragmas): Likewise. * c-common.h (c_omp_depend_t_p, c_finish_omp_depobj): Declare. * c-omp.c (c_omp_depend_t_p, c_finish_omp_depobj): New functions. gcc/c/ * c-parser.c (c_parser_omp_depobj): New function. (c_parser_pragma): Handle PRAGMA_OMP_DEPOBJ. (c_parser_omp_iterators): Return error_mark_node instead of NULL. (c_parser_omp_clause_depend): Make dependence-type optional. * c-typeck.c (c_finish_omp_clauses): Handle depend clause with OMP_CLAUSE_DEPEND_UNSPECIFIED. Diagnose bit-fields. Require omp_depend_t type for OMP_CLAUSE_DEPEND_UNSPECIFIED kinds and some different type for other kinds. Use build_unary_op with ADDR_EXPR and build_indirect_ref instead of c_mark_addressable. gcc/cp/ * parser.c (cp_parser_omp_var_list_no_open): Fix up depend clause error recovery. (cp_parser_omp_iterators): Return error_mark_node instead of NULL. (cp_parser_omp_clause_depend): Make dependence-type optional. (cp_parser_omp_depobj): New function. (cp_parser_pragma): Handle PRAGMA_OMP_DEPOBJ. * cp-tree.h (OMP_DEPOBJ_DEPOBJ, OMP_DEPOBJ_CLAUSES): Define. (finish_omp_depobj): Declare. * cp-tree.def (OMP_DEPOBJ): New tree code. * semantics.c (finish_omp_clauses): Handle depend clause with OMP_CLAUSE_DEPEND_UNSPECIFIED. Diagnose bit-fields. Require omp_depend_t type for OMP_CLAUSE_DEPEND_UNSPECIFIED kinds and some different type for other kinds. Use cp_build_addr_expr and cp_build_indirect_ref instead of cxx_mark_addressable. (finish_omp_depobj): New function. * pt.c (tsubst_expr): Handle OMP_DEPOBJ. * cp-objcp-common.c (cp_common_init_ts): Likewise. * constexpr.c (potential_constant_expression_1): Likewise. * lex.c (cxx_init): Likewise. * dump.c (cp_dump_tree): Likewise. * cxx-pretty-print.c (cxx_pretty_printer::statement): Likewise. gcc/testsuite/ * c-c++-common/gomp/depend-6.c: Add test for bit-field in depend clause. * c-c++-common/gomp/depend-iterator-2.c: Adjust for dependence-type being optional. * c-c++-common/gomp/depobj-1.c: New test. * g++.dg/gomp/depend-iterator-2.C: Adjust for dependence-type being optional. * g++.dg/gomp/depobj-1.C: New test. include/ * gomp-constants.h (GOMP_DEPEND_IN, GOMP_DEPEND_OUT, GOMP_DEPEND_INOUT, GOMP_DEPEND_MUTEXINOUTSET): Define. libgomp/ * omp.h.in (omp_depend_t): New typedef. * task.c (gomp_task_handle_depend): Handle new depend array format in addition to the old. Handle mutexinoutset kinds the same as inout for now, handle unspecified kinds. (gomp_task_maybe_wait_for_dependencies): Likewise. (gomp_create_target_task): Handle new depend array format count in addition to the old. (GOMP_task): Likewise. Adjust function comment. * testsuite/libgomp.c-c++-common/depend-iterator-2.c: New test. * testsuite/libgomp.c-c++-common/depobj-1.c: New test. * testsuite/libgomp.c++/depend-1.C: New test. * testsuite/libgomp.c++/depobj-1.C: New test. --- gcc/tree-core.h.jj 2018-06-05 15:00:56.357957856 +0200 +++ gcc/tree-core.h 2018-06-26 11:46:03.951421363 +0200 @@ -1416,6 +1416,7 @@ struct GTY(()) tree_constructor { enum omp_clause_depend_kind { + OMP_CLAUSE_DEPEND_UNSPECIFIED, OMP_CLAUSE_DEPEND_IN, OMP_CLAUSE_DEPEND_OUT, OMP_CLAUSE_DEPEND_INOUT, --- gcc/gimplify.c.jj 2018-06-18 19:07:09.152186493 +0200 +++ gcc/gimplify.c 2018-06-27 11:33:45.353027093 +0200 @@ -7566,10 +7566,11 @@ gimplify_omp_depend (tree *list_p, gimpl { tree c; gimple *g; - size_t n[2] = { 0, 0 }; - tree counts[2] = { NULL_TREE, NULL_TREE }; + size_t n[4] = { 0, 0, 0, 0 }; + bool unused[4]; + tree counts[4] = { NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE }; tree last_iter = NULL_TREE, last_count = NULL_TREE; - size_t i; + size_t i, j; location_t first_loc = UNKNOWN_LOCATION; for (c = *list_p; c; c = OMP_CLAUSE_CHAIN (c)) @@ -7578,13 +7579,18 @@ gimplify_omp_depend (tree *list_p, gimpl switch (OMP_CLAUSE_DEPEND_KIND (c)) { case OMP_CLAUSE_DEPEND_IN: - i = 0; + i = 2; break; case OMP_CLAUSE_DEPEND_OUT: case OMP_CLAUSE_DEPEND_INOUT: + i = 0; + break; case OMP_CLAUSE_DEPEND_MUTEXINOUTSET: i = 1; break; + case OMP_CLAUSE_DEPEND_UNSPECIFIED: + i = 3; + break; case OMP_CLAUSE_DEPEND_SOURCE: case OMP_CLAUSE_DEPEND_SINK: continue; @@ -7679,10 +7685,16 @@ gimplify_omp_depend (tree *list_p, gimpl else n[i]++; } - if (counts[0] == NULL_TREE && counts[1] == NULL_TREE) + for (i = 0; i < 4; i++) + if (counts[i]) + break; + if (i == 4) return 0; - for (i = 0; i < 2; i++) + + tree total = size_zero_node; + for (i = 0; i < 4; i++) { + unused[i] = counts[i] == NULL_TREE && n[i] == 0; if (counts[i] == NULL_TREE) counts[i] = size_zero_node; if (n[i]) @@ -7690,17 +7702,19 @@ gimplify_omp_depend (tree *list_p, gimpl if (gimplify_expr (&counts[i], pre_p, NULL, is_gimple_val, fb_rvalue) == GS_ERROR) return 2; + total = size_binop (PLUS_EXPR, total, counts[i]); } - tree total = size_binop (PLUS_EXPR, counts[0], counts[1]); if (gimplify_expr (&total, pre_p, NULL, is_gimple_val, fb_rvalue) == GS_ERROR) return 2; - tree totalp1 = size_binop (PLUS_EXPR, unshare_expr (total), size_int (1)); - tree type = build_array_type (ptr_type_node, build_index_type (totalp1)); + bool is_old = unused[1] && unused[3]; + tree totalpx = size_binop (PLUS_EXPR, unshare_expr (total), + size_int (is_old ? 1 : 4)); + tree type = build_array_type (ptr_type_node, build_index_type (totalpx)); tree array = create_tmp_var_raw (type); TREE_ADDRESSABLE (array) = 1; - if (TREE_CODE (totalp1) != INTEGER_CST) + if (TREE_CODE (totalpx) != INTEGER_CST) { if (!TYPE_SIZES_GIMPLIFIED (TREE_TYPE (array))) gimplify_type_sizes (TREE_TYPE (array), pre_p); @@ -7721,21 +7735,52 @@ gimplify_omp_depend (tree *list_p, gimpl gimple_add_tmp_var (array); tree r = build4 (ARRAY_REF, ptr_type_node, array, size_int (0), NULL_TREE, NULL_TREE); - tree tem = build2 (MODIFY_EXPR, void_type_node, r, - fold_convert (ptr_type_node, total)); - gimplify_and_add (tem, pre_p); - r = build4 (ARRAY_REF, ptr_type_node, array, size_int (1), NULL_TREE, - NULL_TREE); - tem = build2 (MODIFY_EXPR, void_type_node, r, counts[1]); + tree tem; + if (!is_old) + { + tem = build2 (MODIFY_EXPR, void_type_node, r, + build_int_cst (ptr_type_node, 0)); + gimplify_and_add (tem, pre_p); + r = build4 (ARRAY_REF, ptr_type_node, array, size_int (1), NULL_TREE, + NULL_TREE); + } + tem = build2 (MODIFY_EXPR, void_type_node, r, + fold_convert (ptr_type_node, total)); gimplify_and_add (tem, pre_p); + for (i = 1; i < (is_old ? 2 : 4); i++) + { + r = build4 (ARRAY_REF, ptr_type_node, array, size_int (i + !is_old), + NULL_TREE, NULL_TREE); + tem = build2 (MODIFY_EXPR, void_type_node, r, counts[i - 1]); + gimplify_and_add (tem, pre_p); + } - tree cnts[2]; - for (i = 0; i < 2; i++) + tree cnts[4]; + for (j = 4; j; j--) + if (!unused[j - 1]) + break; + for (i = 0; i < 4; i++) { + if (i && (i >= j || unused[i - 1])) + { + cnts[i] = cnts[i - 1]; + continue; + } cnts[i] = create_tmp_var (sizetype, NULL); - g = gimple_build_assign (cnts[i], i == 0 ? size_int (2) - : size_binop (PLUS_EXPR, counts[0], - size_int (2))); + if (i == 0) + g = gimple_build_assign (cnts[i], size_int (is_old ? 2 : 5)); + else + { + tree t; + if (is_old) + t = size_binop (PLUS_EXPR, counts[0], size_int (2)); + else + t = size_binop (PLUS_EXPR, cnts[i - 1], counts[i - 1]); + if (gimplify_expr (&t, pre_p, NULL, is_gimple_val, fb_rvalue) + == GS_ERROR) + return 2; + g = gimple_build_assign (cnts[i], t); + } gimple_seq_add_stmt (pre_p, g); } @@ -7748,13 +7793,18 @@ gimplify_omp_depend (tree *list_p, gimpl switch (OMP_CLAUSE_DEPEND_KIND (c)) { case OMP_CLAUSE_DEPEND_IN: - i = 0; + i = 2; break; case OMP_CLAUSE_DEPEND_OUT: case OMP_CLAUSE_DEPEND_INOUT: + i = 0; + break; case OMP_CLAUSE_DEPEND_MUTEXINOUTSET: i = 1; break; + case OMP_CLAUSE_DEPEND_UNSPECIFIED: + i = 3; + break; case OMP_CLAUSE_DEPEND_SOURCE: case OMP_CLAUSE_DEPEND_SINK: continue; @@ -7897,14 +7947,34 @@ gimplify_omp_depend (tree *list_p, gimpl } if (last_bind) gimplify_and_add (last_bind, pre_p); - tree cond = build2_loc (first_loc, NE_EXPR, boolean_type_node, cnts[0], - size_binop_loc (first_loc, PLUS_EXPR, counts[0], - size_int (2))); - cond = build2_loc (first_loc, TRUTH_OR_EXPR, boolean_type_node, cond, - build2_loc (first_loc, NE_EXPR, boolean_type_node, - cnts[1], - size_binop_loc (first_loc, PLUS_EXPR, - totalp1, size_int (1)))); + tree cond = boolean_false_node; + if (is_old) + { + if (!unused[0]) + cond = build2_loc (first_loc, NE_EXPR, boolean_type_node, cnts[0], + size_binop_loc (first_loc, PLUS_EXPR, counts[0], + size_int (2))); + if (!unused[2]) + cond = build2_loc (first_loc, TRUTH_OR_EXPR, boolean_type_node, cond, + build2_loc (first_loc, NE_EXPR, boolean_type_node, + cnts[2], + size_binop_loc (first_loc, PLUS_EXPR, + totalpx, + size_int (1)))); + } + else + { + tree prev = size_int (5); + for (i = 0; i < 4; i++) + { + if (unused[i]) + continue; + prev = size_binop_loc (first_loc, PLUS_EXPR, counts[i], prev); + cond = build2_loc (first_loc, TRUTH_OR_EXPR, boolean_type_node, cond, + build2_loc (first_loc, NE_EXPR, boolean_type_node, + cnts[i], unshare_expr (prev))); + } + } tem = build3_loc (first_loc, COND_EXPR, void_type_node, cond, build_call_expr_loc (first_loc, builtin_decl_explicit (BUILT_IN_TRAP), --- gcc/tree-pretty-print.c.jj 2018-06-18 19:07:09.152186493 +0200 +++ gcc/tree-pretty-print.c 2018-06-26 11:46:03.842421284 +0200 @@ -674,6 +674,9 @@ dump_omp_clause (pretty_printer *pp, tre pp_string (pp, "depend("); switch (OMP_CLAUSE_DEPEND_KIND (clause)) { + case OMP_CLAUSE_DEPEND_UNSPECIFIED: + name = NULL; + break; case OMP_CLAUSE_DEPEND_IN: name = "in"; break; @@ -727,8 +730,11 @@ dump_omp_clause (pretty_printer *pp, tre pp_colon (pp); t = TREE_VALUE (t); } - pp_string (pp, name); - pp_colon (pp); + if (name) + { + pp_string (pp, name); + pp_colon (pp); + } dump_generic_node (pp, t, spc, flags, false); pp_right_paren (pp); } --- gcc/omp-low.c.jj 2018-06-19 08:24:31.960876918 +0200 +++ gcc/omp-low.c 2018-06-26 19:28:36.560929535 +0200 @@ -7351,7 +7351,7 @@ lower_depend_clauses (tree *pclauses, gi { tree c, clauses; gimple *g; - size_t n_in = 0, n_out = 0, idx = 2, i; + size_t cnt[4] = { 0, 0, 0, 0 }, idx = 2, i; clauses = omp_find_clause (*pclauses, OMP_CLAUSE_DEPEND); gcc_assert (clauses); @@ -7363,12 +7363,17 @@ lower_depend_clauses (tree *pclauses, gi /* Lowering already done at gimplification. */ return; case OMP_CLAUSE_DEPEND_IN: - n_in++; + cnt[2]++; break; case OMP_CLAUSE_DEPEND_OUT: case OMP_CLAUSE_DEPEND_INOUT: + cnt[0]++; + break; case OMP_CLAUSE_DEPEND_MUTEXINOUTSET: - n_out++; + cnt[1]++; + break; + case OMP_CLAUSE_DEPEND_UNSPECIFIED: + cnt[3]++; break; case OMP_CLAUSE_DEPEND_SOURCE: case OMP_CLAUSE_DEPEND_SINK: @@ -7376,25 +7381,61 @@ lower_depend_clauses (tree *pclauses, gi default: gcc_unreachable (); } - tree type = build_array_type_nelts (ptr_type_node, n_in + n_out + 2); + if (cnt[1] || cnt[3]) + idx = 5; + size_t total = cnt[0] + cnt[1] + cnt[2] + cnt[3]; + tree type = build_array_type_nelts (ptr_type_node, total + idx); tree array = create_tmp_var (type); TREE_ADDRESSABLE (array) = 1; tree r = build4 (ARRAY_REF, ptr_type_node, array, size_int (0), NULL_TREE, NULL_TREE); - g = gimple_build_assign (r, build_int_cst (ptr_type_node, n_in + n_out)); - gimple_seq_add_stmt (iseq, g); - r = build4 (ARRAY_REF, ptr_type_node, array, size_int (1), NULL_TREE, - NULL_TREE); - g = gimple_build_assign (r, build_int_cst (ptr_type_node, n_out)); + if (idx == 5) + { + g = gimple_build_assign (r, build_int_cst (ptr_type_node, 0)); + gimple_seq_add_stmt (iseq, g); + r = build4 (ARRAY_REF, ptr_type_node, array, size_int (1), NULL_TREE, + NULL_TREE); + } + g = gimple_build_assign (r, build_int_cst (ptr_type_node, total)); gimple_seq_add_stmt (iseq, g); - for (i = 0; i < 2; i++) + for (i = 0; i < (idx == 5 ? 3 : 1); i++) + { + r = build4 (ARRAY_REF, ptr_type_node, array, + size_int (i + 1 + (idx == 5)), NULL_TREE, NULL_TREE); + g = gimple_build_assign (r, build_int_cst (ptr_type_node, cnt[i])); + gimple_seq_add_stmt (iseq, g); + } + for (i = 0; i < 4; i++) { - if ((i ? n_in : n_out) == 0) + if (cnt[i] == 0) continue; for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND - && ((OMP_CLAUSE_DEPEND_KIND (c) != OMP_CLAUSE_DEPEND_IN) ^ i)) + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND) + continue; + else { + switch (OMP_CLAUSE_DEPEND_KIND (c)) + { + case OMP_CLAUSE_DEPEND_IN: + if (i != 2) + continue; + break; + case OMP_CLAUSE_DEPEND_OUT: + case OMP_CLAUSE_DEPEND_INOUT: + if (i != 0) + continue; + break; + case OMP_CLAUSE_DEPEND_MUTEXINOUTSET: + if (i != 1) + continue; + break; + case OMP_CLAUSE_DEPEND_UNSPECIFIED: + if (i != 3) + continue; + break; + default: + gcc_unreachable (); + } tree t = OMP_CLAUSE_DECL (c); t = fold_convert (ptr_type_node, t); gimplify_expr (&t, iseq, NULL, is_gimple_val, fb_rvalue); --- gcc/c-family/c-pragma.h.jj 2018-05-24 18:39:36.408008391 +0200 +++ gcc/c-family/c-pragma.h 2018-06-26 11:46:03.898421325 +0200 @@ -47,6 +47,7 @@ enum pragma_kind { PRAGMA_OMP_CANCELLATION_POINT, PRAGMA_OMP_CRITICAL, PRAGMA_OMP_DECLARE, + PRAGMA_OMP_DEPOBJ, PRAGMA_OMP_DISTRIBUTE, PRAGMA_OMP_END_DECLARE_TARGET, PRAGMA_OMP_FLUSH, --- gcc/c-family/c-pragma.c.jj 2018-05-30 10:16:26.973224443 +0200 +++ gcc/c-family/c-pragma.c 2018-06-26 11:46:03.937421353 +0200 @@ -1286,6 +1286,7 @@ static const struct omp_pragma_def omp_p { "cancel", PRAGMA_OMP_CANCEL }, { "cancellation", PRAGMA_OMP_CANCELLATION_POINT }, { "critical", PRAGMA_OMP_CRITICAL }, + { "depobj", PRAGMA_OMP_DEPOBJ }, { "end", PRAGMA_OMP_END_DECLARE_TARGET }, { "flush", PRAGMA_OMP_FLUSH }, { "master", PRAGMA_OMP_MASTER }, --- gcc/c-family/c-common.h.jj 2018-06-19 10:42:21.289381950 +0200 +++ gcc/c-family/c-common.h 2018-06-26 15:06:55.976139163 +0200 @@ -1149,6 +1149,9 @@ extern void c_finish_omp_barrier (locati extern tree c_finish_omp_atomic (location_t, enum tree_code, enum tree_code, tree, tree, tree, tree, tree, bool, enum omp_memory_order, bool = false); +extern bool c_omp_depend_t_p (tree); +extern void c_finish_omp_depobj (location_t, tree, enum omp_clause_depend_kind, + tree); extern void c_finish_omp_flush (location_t, int); extern void c_finish_omp_taskwait (location_t); extern void c_finish_omp_taskyield (location_t); --- gcc/c-family/c-omp.c.jj 2018-06-19 10:42:21.290381951 +0200 +++ gcc/c-family/c-omp.c 2018-06-28 12:52:35.420378922 +0200 @@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. #include "c-common.h" #include "gimple-expr.h" #include "c-pragma.h" +#include "stringpool.h" #include "omp-general.h" #include "gomp-constants.h" #include "memmodel.h" @@ -417,6 +418,153 @@ c_finish_omp_atomic (location_t loc, enu } +/* Return true if TYPE is the implementation's omp_depend_t. */ + +bool +c_omp_depend_t_p (tree type) +{ + type = TYPE_MAIN_VARIANT (type); + return (TREE_CODE (type) == RECORD_TYPE + && TYPE_NAME (type) + && ((TREE_CODE (TYPE_NAME (type)) == TYPE_DECL + ? DECL_NAME (TYPE_NAME (type)) : TYPE_NAME (type)) + == get_identifier ("omp_depend_t")) + && (!TYPE_CONTEXT (type) + || TREE_CODE (TYPE_CONTEXT (type)) == TRANSLATION_UNIT_DECL) + && COMPLETE_TYPE_P (type) + && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST + && !compare_tree_int (TYPE_SIZE (type), + 2 * tree_to_uhwi (TYPE_SIZE (ptr_type_node)))); +} + + +/* Complete a #pragma omp depobj construct. LOC is the location of the + #pragma. */ + +void +c_finish_omp_depobj (location_t loc, tree depobj, + enum omp_clause_depend_kind kind, tree clause) +{ + tree t = NULL_TREE; + if (!error_operand_p (depobj)) + { + if (!c_omp_depend_t_p (TREE_TYPE (depobj))) + { + error_at (EXPR_LOC_OR_LOC (depobj, loc), + "type of %<depobj%> expression is not %<omp_depend_t%>"); + depobj = error_mark_node; + } + else if (TYPE_READONLY (TREE_TYPE (depobj))) + { + error_at (EXPR_LOC_OR_LOC (depobj, loc), + "%<const%> qualified %<depobj%> expression"); + depobj = error_mark_node; + } + } + else + depobj = error_mark_node; + + if (clause == error_mark_node) + return; + + if (clause) + { + gcc_assert (TREE_CODE (clause) == OMP_CLAUSE + && OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_DEPEND); + if (OMP_CLAUSE_CHAIN (clause)) + error_at (OMP_CLAUSE_LOCATION (clause), + "more than one locator in %<depend%> clause on %<depobj%> " + "construct"); + switch (OMP_CLAUSE_DEPEND_KIND (clause)) + { + case OMP_CLAUSE_DEPEND_UNSPECIFIED: + error_at (OMP_CLAUSE_LOCATION (clause), + "dependence type must be specified in %<depend%> clause " + "on %<depobj%> construct"); + return; + case OMP_CLAUSE_DEPEND_SOURCE: + case OMP_CLAUSE_DEPEND_SINK: + error_at (OMP_CLAUSE_LOCATION (clause), + "%<depend(%s)%> is only allowed in %<omp ordered%>", + OMP_CLAUSE_DEPEND_KIND (clause) == OMP_CLAUSE_DEPEND_SOURCE + ? "source" : "sink"); + return; + case OMP_CLAUSE_DEPEND_IN: + case OMP_CLAUSE_DEPEND_OUT: + case OMP_CLAUSE_DEPEND_INOUT: + case OMP_CLAUSE_DEPEND_MUTEXINOUTSET: + kind = OMP_CLAUSE_DEPEND_KIND (clause); + t = OMP_CLAUSE_DECL (clause); + gcc_assert (t); + if (TREE_CODE (t) == TREE_LIST + && TREE_PURPOSE (t) + && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC) + { + error_at (OMP_CLAUSE_LOCATION (clause), + "%<iterator%> modifier may not be specified on " + "%<depobj%> construct"); + return; + } + if (TREE_CODE (t) == COMPOUND_EXPR) + { + tree t1 = build_fold_addr_expr (TREE_OPERAND (t, 1)); + t = build2 (COMPOUND_EXPR, TREE_TYPE (t1), TREE_OPERAND (t, 0), + t1); + } + else + t = build_fold_addr_expr (t); + break; + default: + gcc_unreachable (); + } + } + else + gcc_assert (kind != OMP_CLAUSE_DEPEND_UNSPECIFIED); + + if (depobj == error_mark_node) + return; + + depobj = build_fold_addr_expr_loc (EXPR_LOC_OR_LOC (depobj, loc), depobj); + tree dtype + = build_pointer_type_for_mode (ptr_type_node, TYPE_MODE (ptr_type_node), + true); + depobj = fold_convert (dtype, depobj); + tree r; + if (clause) + { + depobj = save_expr (depobj); + r = build_indirect_ref (loc, depobj, RO_UNARY_STAR); + add_stmt (build2 (MODIFY_EXPR, void_type_node, r, t)); + } + int k; + switch (kind) + { + case OMP_CLAUSE_DEPEND_IN: + k = GOMP_DEPEND_IN; + break; + case OMP_CLAUSE_DEPEND_OUT: + k = GOMP_DEPEND_OUT; + break; + case OMP_CLAUSE_DEPEND_INOUT: + k = GOMP_DEPEND_INOUT; + break; + case OMP_CLAUSE_DEPEND_MUTEXINOUTSET: + k = GOMP_DEPEND_MUTEXINOUTSET; + break; + case OMP_CLAUSE_DEPEND_LAST: + k = -1; + break; + default: + gcc_unreachable (); + } + t = build_int_cst (ptr_type_node, k); + depobj = build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (depobj), depobj, + TYPE_SIZE_UNIT (ptr_type_node)); + r = build_indirect_ref (loc, depobj, RO_UNARY_STAR); + add_stmt (build2 (MODIFY_EXPR, void_type_node, r, t)); +} + + /* Complete a #pragma omp flush construct. We don't do anything with the variable list that the syntax allows. LOC is the location of the #pragma. */ --- gcc/c/c-parser.c.jj 2018-06-19 10:42:21.288381950 +0200 +++ gcc/c/c-parser.c 2018-06-28 10:06:16.079468470 +0200 @@ -1446,6 +1446,7 @@ static void c_parser_oacc_update (c_pars static void c_parser_omp_construct (c_parser *, bool *); static void c_parser_omp_threadprivate (c_parser *); static void c_parser_omp_barrier (c_parser *); +static void c_parser_omp_depobj (c_parser *); static void c_parser_omp_flush (c_parser *); static tree c_parser_omp_for_loop (location_t, c_parser *, enum tree_code, tree, tree *, bool *); @@ -10999,6 +11000,15 @@ c_parser_pragma (c_parser *parser, enum c_parser_omp_barrier (parser); return false; + case PRAGMA_OMP_DEPOBJ: + if (context != pragma_compound) + { + construct = "omp depobj"; + goto in_compound; + } + c_parser_omp_depobj (parser); + return false; + case PRAGMA_OMP_FLUSH: if (context != pragma_compound) { @@ -13900,7 +13910,7 @@ c_parser_omp_iterators (c_parser *parser while (1); parens.skip_until_found_close (parser); - return ret; + return ret ? ret : error_mark_node; } /* OpenMP 4.0: @@ -13918,7 +13928,7 @@ static tree c_parser_omp_clause_depend (c_parser *parser, tree list) { location_t clause_loc = c_parser_peek_token (parser)->location; - enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INOUT; + enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_UNSPECIFIED; tree nl, c, iterators = NULL_TREE; matching_parens parens; @@ -13928,9 +13938,31 @@ c_parser_omp_clause_depend (c_parser *pa do { if (c_parser_next_token_is_not (parser, CPP_NAME)) - goto invalid_kind; + break; const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp ("iterator", p) == 0 + && iterators == NULL_TREE + && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN) + { + /* FIXME: if depend kind remains optional, this is ambiguous + and we'd need to do tentative parsing to distinguish between + valid iterator modifier and just normal expression starting + with iterator ( tokens. Not doing it right now, as I hope + it will become mandatory. */ + iterators = c_parser_omp_iterators (parser); + c_parser_require (parser, CPP_COLON, "expected %<:%>"); + continue; + } + if (strcmp ("source", p) == 0 + && c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_PAREN) + { + /* FIXME: this is another ambiguity. */ + kind = OMP_CLAUSE_DEPEND_SOURCE; + break; + } + if (c_parser_peek_2nd_token (parser)->type != CPP_COLON) + break; if (strcmp ("in", p) == 0) kind = OMP_CLAUSE_DEPEND_IN; else if (strcmp ("inout", p) == 0) @@ -13939,23 +13971,16 @@ c_parser_omp_clause_depend (c_parser *pa kind = OMP_CLAUSE_DEPEND_MUTEXINOUTSET; else if (strcmp ("out", p) == 0) kind = OMP_CLAUSE_DEPEND_OUT; - else if (strcmp ("source", p) == 0) - kind = OMP_CLAUSE_DEPEND_SOURCE; else if (strcmp ("sink", p) == 0) kind = OMP_CLAUSE_DEPEND_SINK; - else if (strcmp ("iterator", p) == 0 && iterators == NULL_TREE) - { - iterators = c_parser_omp_iterators (parser); - c_parser_require (parser, CPP_COLON, "expected %<:%>"); - continue; - } else goto invalid_kind; break; } while (1); - c_parser_consume_token (parser); + if (kind != OMP_CLAUSE_DEPEND_UNSPECIFIED) + c_parser_consume_token (parser); if (iterators && (kind == OMP_CLAUSE_DEPEND_SOURCE || kind == OMP_CLAUSE_DEPEND_SINK)) @@ -13976,7 +14001,8 @@ c_parser_omp_clause_depend (c_parser *pa return c; } - if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + if (kind != OMP_CLAUSE_DEPEND_UNSPECIFIED + && !c_parser_require (parser, CPP_COLON, "expected %<:%>")) goto resync_fail; if (kind == OMP_CLAUSE_DEPEND_SINK) @@ -16106,6 +16132,115 @@ c_parser_omp_critical (location_t loc, c return c_finish_omp_critical (loc, stmt, name, clauses); } +/* OpenMP 5.0: + # pragma omp depobj ( depobj ) depobj-clause new-line + + depobj-clause: + depend (dependence-type : locator) + destroy + update (dependence-type) + + dependence-type: + in + out + inout + mutexinout */ + +static void +c_parser_omp_depobj (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + c_parser_consume_pragma (parser); + matching_parens parens; + if (!parens.require_open (parser)) + { + c_parser_skip_to_pragma_eol (parser); + return; + } + + tree depobj = c_parser_expr_no_commas (parser, NULL).value; + if (depobj != error_mark_node) + { + if (!lvalue_p (depobj)) + { + error_at (EXPR_LOC_OR_LOC (depobj, loc), + "%<depobj%> expression is not lvalue expression"); + depobj = error_mark_node; + } + else + { + tree addr = build_unary_op (EXPR_LOC_OR_LOC (depobj, loc), ADDR_EXPR, + depobj, false); + if (addr == error_mark_node) + depobj = error_mark_node; + else + depobj = build_indirect_ref (EXPR_LOC_OR_LOC (depobj, loc), + addr, RO_UNARY_STAR); + } + } + + parens.skip_until_found_close (parser); + tree clause = NULL_TREE; + enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_UNSPECIFIED; + location_t c_loc = c_parser_peek_token (parser)->location; + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + c_parser_consume_token (parser); + if (!strcmp ("depend", p)) + { + clause = c_parser_omp_clause_depend (parser, NULL_TREE); + clause = c_finish_omp_clauses (clause, C_ORT_OMP); + if (!clause) + clause = error_mark_node; + } + else if (!strcmp ("destroy", p)) + kind = OMP_CLAUSE_DEPEND_LAST; + else if (!strcmp ("update", p)) + { + matching_parens c_parens; + if (c_parens.require_open (parser)) + { + location_t c2_loc = c_parser_peek_token (parser)->location; + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p2 + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + c_parser_consume_token (parser); + if (!strcmp ("in", p2)) + kind = OMP_CLAUSE_DEPEND_IN; + else if (!strcmp ("out", p2)) + kind = OMP_CLAUSE_DEPEND_OUT; + else if (!strcmp ("inout", p2)) + kind = OMP_CLAUSE_DEPEND_INOUT; + else if (!strcmp ("mutexinoutset", p2)) + kind = OMP_CLAUSE_DEPEND_MUTEXINOUTSET; + } + if (kind == OMP_CLAUSE_DEPEND_UNSPECIFIED) + { + clause = error_mark_node; + error_at (c2_loc, "expected %<in%>, %<out%>, %<inout%> or " + "%<mutexinoutset%>"); + } + c_parens.skip_until_found_close (parser); + } + else + clause = error_mark_node; + } + } + if (!clause && kind == OMP_CLAUSE_DEPEND_UNSPECIFIED) + { + clause = error_mark_node; + error_at (c_loc, "expected %<depend%>, %<destroy%> or %<update%> clause"); + } + c_parser_skip_to_pragma_eol (parser); + + c_finish_omp_depobj (loc, depobj, kind, clause); +} + + /* OpenMP 2.5: # pragma omp flush flush-vars[opt] new-line --- gcc/c/c-typeck.c.jj 2018-06-13 18:21:54.220430042 +0200 +++ gcc/c/c-typeck.c 2018-06-28 13:59:50.451669508 +0200 @@ -13771,6 +13771,14 @@ c_finish_omp_clauses (tree clauses, enum { if (handle_omp_array_sections (c, ort)) remove = true; + else if (OMP_CLAUSE_DEPEND_KIND (c) + == OMP_CLAUSE_DEPEND_UNSPECIFIED) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%<depend%> clause without dependence type " + "on array section"); + remove = true; + } break; } if (t == error_mark_node) @@ -13782,8 +13790,51 @@ c_finish_omp_clauses (tree clauses, enum "%<depend%> clause", t); remove = true; } - else if (!c_mark_addressable (t)) - remove = true; + else if (TREE_CODE (t) == COMPONENT_REF + && DECL_C_BIT_FIELD (TREE_OPERAND (t, 1))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "bit-field %qE in %qs clause", t, "depend"); + remove = true; + } + else if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_UNSPECIFIED) + { + if (!c_omp_depend_t_p (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE does not have %<omp_depend_t%> type in " + "%<depend%> clause without dependence type", t); + remove = true; + } + } + else if (c_omp_depend_t_p (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE should not have %<omp_depend_t%> type in " + "%<depend%> clause with dependence type", t); + remove = true; + } + if (!remove) + { + tree addr = build_unary_op (OMP_CLAUSE_LOCATION (c), ADDR_EXPR, + t, false); + if (addr == error_mark_node) + remove = true; + else + { + 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; + } + } break; case OMP_CLAUSE_MAP: --- gcc/cp/parser.c.jj 2018-06-19 10:42:21.296381957 +0200 +++ gcc/cp/parser.c 2018-06-28 12:29:49.355395472 +0200 @@ -31619,8 +31619,13 @@ cp_parser_omp_var_list_no_open (cp_parse else decl = name; if (decl == error_mark_node) - cp_parser_name_lookup_error (parser, name, decl, NLE_NULL, - token->location); + { + if (kind == OMP_CLAUSE_DEPEND + && cp_parser_simulate_error (parser)) + goto depend_lvalue; + cp_parser_name_lookup_error (parser, name, decl, NLE_NULL, + token->location); + } } if (decl == error_mark_node) ; @@ -33708,7 +33713,7 @@ cp_parser_omp_iterators (cp_parser *pars /*or_comma=*/false, /*consume_paren=*/true); - return ret; + return ret ? ret : error_mark_node; } /* OpenMP 4.0: @@ -33726,7 +33731,7 @@ static tree cp_parser_omp_clause_depend (cp_parser *parser, tree list, location_t loc) { tree nlist, c, iterators = NULL_TREE; - enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INOUT; + enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_UNSPECIFIED; matching_parens parens; if (!parens.require_open (parser)) @@ -33735,11 +33740,44 @@ cp_parser_omp_clause_depend (cp_parser * do { if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME)) - goto invalid_kind; + break; tree id = cp_lexer_peek_token (parser->lexer)->u.value; const char *p = IDENTIFIER_POINTER (id); + if (strcmp ("iterator", p) == 0 + && iterators == NULL_TREE + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_PAREN)) + { + cp_lexer_save_tokens (parser->lexer); + cp_lexer_consume_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); + bool is_iter + = (cp_parser_skip_to_closing_parenthesis (parser, false, false, + /*consume_paren=*/true) + && cp_lexer_next_token_is (parser->lexer, CPP_COLON)); + + /* Roll back the tokens we skipped. */ + cp_lexer_rollback_tokens (parser->lexer); + + if (is_iter) + { + begin_scope (sk_omp, NULL); + iterators = cp_parser_omp_iterators (parser); + cp_parser_require (parser, CPP_COLON, RT_COLON); + continue; + } + } + if (strcmp ("source", p) == 0 + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_CLOSE_PAREN)) + { + /* FIXME: this is ambiguous. */ + kind = OMP_CLAUSE_DEPEND_SOURCE; + break; + } + + if (!cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON)) + break; if (strcmp ("in", p) == 0) kind = OMP_CLAUSE_DEPEND_IN; else if (strcmp ("inout", p) == 0) @@ -33748,24 +33786,16 @@ cp_parser_omp_clause_depend (cp_parser * kind = OMP_CLAUSE_DEPEND_MUTEXINOUTSET; else if (strcmp ("out", p) == 0) kind = OMP_CLAUSE_DEPEND_OUT; - else if (strcmp ("source", p) == 0) - kind = OMP_CLAUSE_DEPEND_SOURCE; else if (strcmp ("sink", p) == 0) kind = OMP_CLAUSE_DEPEND_SINK; - else if (strcmp ("iterator", p) == 0 && iterators == NULL_TREE) - { - begin_scope (sk_omp, NULL); - iterators = cp_parser_omp_iterators (parser); - cp_parser_require (parser, CPP_COLON, RT_COLON); - continue; - } else goto invalid_kind; break; } while (1); - cp_lexer_consume_token (parser->lexer); + if (kind != OMP_CLAUSE_DEPEND_UNSPECIFIED) + cp_lexer_consume_token (parser->lexer); if (iterators && (kind == OMP_CLAUSE_DEPEND_SOURCE || kind == OMP_CLAUSE_DEPEND_SINK)) @@ -33789,7 +33819,8 @@ cp_parser_omp_clause_depend (cp_parser * return c; } - if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) + if (kind != OMP_CLAUSE_DEPEND_UNSPECIFIED + && !cp_parser_require (parser, CPP_COLON, RT_COLON)) goto resync_fail; if (kind == OMP_CLAUSE_DEPEND_SINK) @@ -35253,6 +35284,106 @@ cp_parser_omp_critical (cp_parser *parse return c_finish_omp_critical (input_location, stmt, name, clauses); } +/* OpenMP 5.0: + # pragma omp depobj ( depobj ) depobj-clause new-line + + depobj-clause: + depend (dependence-type : locator) + destroy + update (dependence-type) + + dependence-type: + in + out + inout + mutexinout */ + +static void +cp_parser_omp_depobj (cp_parser *parser, cp_token *pragma_tok) +{ + location_t loc = pragma_tok->location; + matching_parens parens; + if (!parens.require_open (parser)) + { + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return; + } + + tree depobj = cp_parser_assignment_expression (parser); + + if (!parens.require_close (parser)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + tree clause = NULL_TREE; + enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_UNSPECIFIED; + location_t c_loc = cp_lexer_peek_token (parser->lexer)->location; + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + + cp_lexer_consume_token (parser->lexer); + if (!strcmp ("depend", p)) + { + clause = cp_parser_omp_clause_depend (parser, NULL_TREE, c_loc); + if (clause) + clause = finish_omp_clauses (clause, C_ORT_OMP); + if (!clause) + clause = error_mark_node; + } + else if (!strcmp ("destroy", p)) + kind = OMP_CLAUSE_DEPEND_LAST; + else if (!strcmp ("update", p)) + { + matching_parens c_parens; + if (c_parens.require_open (parser)) + { + location_t c2_loc + = cp_lexer_peek_token (parser->lexer)->location; + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id2 = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p2 = IDENTIFIER_POINTER (id2); + + cp_lexer_consume_token (parser->lexer); + if (!strcmp ("in", p2)) + kind = OMP_CLAUSE_DEPEND_IN; + else if (!strcmp ("out", p2)) + kind = OMP_CLAUSE_DEPEND_OUT; + else if (!strcmp ("inout", p2)) + kind = OMP_CLAUSE_DEPEND_INOUT; + else if (!strcmp ("mutexinoutset", p2)) + kind = OMP_CLAUSE_DEPEND_MUTEXINOUTSET; + } + if (kind == OMP_CLAUSE_DEPEND_UNSPECIFIED) + { + clause = error_mark_node; + error_at (c2_loc, "expected %<in%>, %<out%>, %<inout%> or " + "%<mutexinoutset%>"); + } + if (!c_parens.require_close (parser)) + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + } + else + clause = error_mark_node; + } + } + if (!clause && kind == OMP_CLAUSE_DEPEND_UNSPECIFIED) + { + clause = error_mark_node; + error_at (c_loc, "expected %<depend%>, %<destroy%> or %<update%> clause"); + } + cp_parser_require_pragma_eol (parser, pragma_tok); + + finish_omp_depobj (loc, depobj, kind, clause); +} + + /* OpenMP 2.5: # pragma omp flush flush-vars[opt] new-line @@ -39499,6 +39630,21 @@ cp_parser_pragma (cp_parser *parser, enu break; default: goto bad_stmt; + } + break; + + case PRAGMA_OMP_DEPOBJ: + switch (context) + { + case pragma_compound: + cp_parser_omp_depobj (parser, pragma_tok); + return false; + case pragma_stmt: + error_at (pragma_tok->location, "%<#pragma %s%> may only be " + "used in compound statements", "omp depobj"); + break; + default: + goto bad_stmt; } break; --- gcc/cp/cp-tree.h.jj 2018-06-19 10:42:21.292381953 +0200 +++ gcc/cp/cp-tree.h 2018-06-27 18:34:55.947148174 +0200 @@ -4953,6 +4953,13 @@ more_aggr_init_expr_args_p (const aggr_i #define ALIGNOF_EXPR_STD_P(NODE) \ TREE_LANG_FLAG_0 (ALIGNOF_EXPR_CHECK (NODE)) +/* OMP_DEPOBJ accessors. These give access to the depobj expression of the + #pragma omp depobj directive and the clauses, respectively. If + OMP_DEPOBJ_CLAUSES is INTEGER_CST, it is instead the update clause kind + or OMP_CLAUSE_DEPEND_LAST for destroy clause. */ +#define OMP_DEPOBJ_DEPOBJ(NODE) TREE_OPERAND (OMP_DEPOBJ_CHECK (NODE), 0) +#define OMP_DEPOBJ_CLAUSES(NODE) TREE_OPERAND (OMP_DEPOBJ_CHECK (NODE), 1) + /* An enumeration of the kind of tags that C++ accepts. */ enum tag_types { none_type = 0, /* Not a tag type. */ @@ -6968,6 +6975,9 @@ extern void finish_omp_atomic (enum tr tree, tree, tree, tree, tree, tree, enum omp_memory_order); extern void finish_omp_barrier (void); +extern void finish_omp_depobj (location_t, tree, + enum omp_clause_depend_kind, + tree); extern void finish_omp_flush (int); extern void finish_omp_taskwait (void); extern void finish_omp_taskyield (void); --- gcc/cp/cp-tree.def.jj 2018-04-30 14:08:47.954326097 +0200 +++ gcc/cp/cp-tree.def 2018-06-27 18:17:40.422318868 +0200 @@ -498,6 +498,11 @@ DEFTREECODE (BASES, "bases", tcc_type, 0 instantiation time. */ DEFTREECODE (TEMPLATE_INFO, "template_info", tcc_exceptional, 0) +/* OpenMP - #pragma omp depobj + Operand 0: OMP_DEPOBJ_DEPOBJ: Depobj expression + Operand 1: OMP_DEPOBJ_CLAUSES: List of clauses. */ +DEFTREECODE (OMP_DEPOBJ, "omp_depobj", tcc_statement, 2) + /* Extensions for Concepts. */ /* Used to represent information associated with constrained declarations. */ --- gcc/cp/semantics.c.jj 2018-06-19 10:42:21.297381958 +0200 +++ gcc/cp/semantics.c 2018-06-28 14:03:15.283848339 +0200 @@ -6837,6 +6837,14 @@ finish_omp_clauses (tree clauses, enum c { if (handle_omp_array_sections (c, ort)) remove = true; + else if (OMP_CLAUSE_DEPEND_KIND (c) + == OMP_CLAUSE_DEPEND_UNSPECIFIED) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%<depend%> clause without dependence type " + "on array section"); + remove = true; + } break; } if (t == error_mark_node) @@ -6862,8 +6870,55 @@ finish_omp_clauses (tree clauses, enum c "in %<depend%> clause", t); remove = true; } - else if (!cxx_mark_addressable (t)) - remove = true; + else if (TREE_CODE (t) == COMPONENT_REF + && TREE_CODE (TREE_OPERAND (t, 1)) == FIELD_DECL + && DECL_BIT_FIELD (TREE_OPERAND (t, 1))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "bit-field %qE in %qs clause", t, "depend"); + remove = true; + } + else if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_UNSPECIFIED) + { + if (!c_omp_depend_t_p (TYPE_REF_P (TREE_TYPE (t)) + ? TREE_TYPE (TREE_TYPE (t)) + : TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE does not have %<omp_depend_t%> type in " + "%<depend%> clause without dependence type", t); + remove = true; + } + } + else if (c_omp_depend_t_p (TYPE_REF_P (TREE_TYPE (t)) + ? TREE_TYPE (TREE_TYPE (t)) + : TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE should not have %<omp_depend_t%> type in " + "%<depend%> clause with dependence type", t); + remove = true; + } + if (!remove) + { + tree addr = cp_build_addr_expr (t, tf_warning_or_error); + if (addr == error_mark_node) + remove = true; + else + { + t = cp_build_indirect_ref (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; + } + } break; case OMP_CLAUSE_MAP: @@ -8755,6 +8810,41 @@ finish_omp_barrier (void) } void +finish_omp_depobj (location_t loc, tree depobj, + enum omp_clause_depend_kind kind, tree clause) +{ + if (!error_operand_p (depobj) && !type_dependent_expression_p (depobj)) + { + if (!lvalue_p (depobj)) + { + error_at (EXPR_LOC_OR_LOC (depobj, loc), + "%<depobj%> expression is not lvalue expression"); + depobj = error_mark_node; + } + } + + if (processing_template_decl) + { + if (clause == NULL_TREE) + clause = build_int_cst (integer_type_node, kind); + add_stmt (build_min_nt_loc (loc, OMP_DEPOBJ, depobj, clause)); + return; + } + + if (!error_operand_p (depobj)) + { + tree addr = cp_build_addr_expr (depobj, tf_warning_or_error); + if (addr == error_mark_node) + depobj = error_mark_node; + else + depobj = cp_build_indirect_ref (addr, RO_UNARY_STAR, + tf_warning_or_error); + } + + c_finish_omp_depobj (loc, depobj, kind, clause); +} + +void finish_omp_flush (int mo) { tree fn = builtin_decl_explicit (BUILT_IN_SYNC_SYNCHRONIZE); --- gcc/cp/pt.c.jj 2018-06-18 19:07:09.152186493 +0200 +++ gcc/cp/pt.c 2018-06-28 14:34:46.605431819 +0200 @@ -17237,6 +17237,32 @@ tsubst_expr (tree t, tree args, tsubst_f pop_omp_privatization_clauses (r); break; + case OMP_DEPOBJ: + r = RECUR (OMP_DEPOBJ_DEPOBJ (t)); + if (OMP_DEPOBJ_CLAUSES (t) && OMP_DEPOBJ_CLAUSES (t) != error_mark_node) + { + enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_UNSPECIFIED; + if (TREE_CODE (OMP_DEPOBJ_CLAUSES (t)) == OMP_CLAUSE) + { + tmp = tsubst_omp_clauses (OMP_DEPOBJ_CLAUSES (t), C_ORT_OMP, + args, complain, in_decl); + if (tmp == NULL_TREE) + tmp = error_mark_node; + } + else + { + kind = (enum omp_clause_depend_kind) + tree_to_uhwi (OMP_DEPOBJ_CLAUSES (t)); + tmp = NULL_TREE; + } + finish_omp_depobj (EXPR_LOCATION (t), r, kind, tmp); + } + else + finish_omp_depobj (EXPR_LOCATION (t), r, + OMP_CLAUSE_DEPEND_UNSPECIFIED, + OMP_DEPOBJ_CLAUSES (t)); + break; + case OACC_DATA: case OMP_TARGET_DATA: case OMP_TARGET: --- gcc/cp/cp-objcp-common.c.jj 2018-06-04 18:17:55.714534653 +0200 +++ gcc/cp/cp-objcp-common.c 2018-06-27 18:22:48.515565607 +0200 @@ -446,6 +446,7 @@ cp_common_init_ts (void) MARK_TS_TYPED (UNARY_RIGHT_FOLD_EXPR); MARK_TS_TYPED (BINARY_LEFT_FOLD_EXPR); MARK_TS_TYPED (BINARY_RIGHT_FOLD_EXPR); + MARK_TS_TYPED (OMP_DEPOBJ); } #include "gt-cp-cp-objcp-common.h" --- gcc/cp/constexpr.c.jj 2018-06-04 18:17:50.495526420 +0200 +++ gcc/cp/constexpr.c 2018-06-27 18:43:59.314583341 +0200 @@ -5730,6 +5730,7 @@ potential_constant_expression_1 (tree t, case OMP_ATOMIC_READ: case OMP_ATOMIC_CAPTURE_OLD: case OMP_ATOMIC_CAPTURE_NEW: + case OMP_DEPOBJ: case OACC_PARALLEL: case OACC_KERNELS: case OACC_DATA: --- gcc/cp/lex.c.jj 2018-04-30 14:08:50.527332447 +0200 +++ gcc/cp/lex.c 2018-06-27 19:00:21.374380858 +0200 @@ -289,7 +289,7 @@ cxx_init (void) IF_STMT, CLEANUP_STMT, FOR_STMT, RANGE_FOR_STMT, WHILE_STMT, DO_STMT, BREAK_STMT, CONTINUE_STMT, SWITCH_STMT, - EXPR_STMT + EXPR_STMT, OMP_DEPOBJ }; memset (&statement_code_p, 0, sizeof (statement_code_p)); --- gcc/cp/dump.c.jj 2018-04-30 14:08:49.863330809 +0200 +++ gcc/cp/dump.c 2018-06-27 18:59:46.905352523 +0200 @@ -327,6 +327,12 @@ cp_dump_tree (void* dump_info, tree t) dump_child ("expr", EXPR_STMT_EXPR (t)); break; + case OMP_DEPOBJ: + dump_stmt (di, t); + dump_child ("depobj", OMP_DEPOBJ_DEPOBJ (t)); + dump_child ("clauses", OMP_DEPOBJ_CLAUSES (t)); + break; + default: break; } --- gcc/cp/cxx-pretty-print.c.jj 2018-06-04 18:17:52.265529212 +0200 +++ gcc/cp/cxx-pretty-print.c 2018-06-28 11:06:51.810642952 +0200 @@ -2068,6 +2068,42 @@ cxx_pretty_printer::statement (tree t) declaration (t); break; + case OMP_DEPOBJ: + pp_cxx_ws_string (this, "#pragma omp depobj"); + pp_space (this); + pp_cxx_left_paren (this); + expression (OMP_DEPOBJ_DEPOBJ (t)); + pp_cxx_right_paren (this); + if (OMP_DEPOBJ_CLAUSES (t) && OMP_DEPOBJ_CLAUSES (t) != error_mark_node) + { + if (TREE_CODE (OMP_DEPOBJ_CLAUSES (t)) == OMP_CLAUSE) + dump_omp_clauses (this, OMP_DEPOBJ_CLAUSES (t), + pp_indentation (this), 0); + else + switch (tree_to_uhwi (OMP_DEPOBJ_CLAUSES (t))) + { + case OMP_CLAUSE_DEPEND_IN: + pp_cxx_ws_string (this, " update(in)"); + break; + case OMP_CLAUSE_DEPEND_INOUT: + pp_cxx_ws_string (this, " update(inout)"); + break; + case OMP_CLAUSE_DEPEND_OUT: + pp_cxx_ws_string (this, " update(out)"); + break; + case OMP_CLAUSE_DEPEND_MUTEXINOUTSET: + pp_cxx_ws_string (this, " update(mutexinoutset)"); + break; + case OMP_CLAUSE_DEPEND_LAST: + pp_cxx_ws_string (this, " destroy"); + break; + default: + break; + } + } + pp_needs_newline (this) = true; + break; + default: c_pretty_printer::statement (t); break; --- gcc/testsuite/c-c++-common/gomp/depend-6.c.jj 2017-05-09 14:13:58.002191451 +0200 +++ gcc/testsuite/c-c++-common/gomp/depend-6.c 2018-06-28 13:15:15.441402972 +0200 @@ -3,10 +3,12 @@ struct T { int c[3]; }; struct S { int a; struct T *b; struct T g; }; +struct U { int a : 5; }; struct S d[10]; struct S *e[10]; struct S *f; struct S h; +struct U i; void foo (void) @@ -29,4 +31,6 @@ foo (void) ; #pragma omp task depend(inout: h.g.c[2:1]) /* { dg-error "expected" } */ ; + #pragma omp task depend(in: i.a) /* { dg-error "bit-field '\[^\n\r]*' in 'depend' clause" } */ + ; } --- gcc/testsuite/c-c++-common/gomp/depend-iterator-2.c.jj 2018-06-13 18:27:33.876741370 +0200 +++ gcc/testsuite/c-c++-common/gomp/depend-iterator-2.c 2018-06-28 13:07:08.721033484 +0200 @@ -7,7 +7,7 @@ int *h; void f1 (void) { - #pragma omp task depend (iterator : in : a) /* { dg-error "expected" } */ + #pragma omp task depend (iterator : in : a) /* { dg-error "expected|invalid depend kind" } */ ; #pragma omp task depend (iterator (for = 0 : 2) : in : a) /* { dg-error "expected" } */ ; @@ -25,9 +25,7 @@ f1 (void) ; #pragma omp task depend (iterator (i = 0 : 10 : 2, 3) : in : a) /* { dg-error "expected" } */ ; - #pragma omp task depend (iterator (i = 0:1), iterator (j = 0:1) : in : a) /* { dg-error "expected ':'|invalid depend kind" } */ - ; - #pragma omp task depend (iterator (i = 0:1): iterator (j = 0:1) : in : a) /* { dg-error "invalid depend kind" } */ + #pragma omp task depend (iterator (i = 0:1), iterator (j = 0:1) : in : a) /* { dg-error "expected ':'|invalid depend kind|'iterator' undeclared|was not declared|expected '\\)' before ':' token" } */ ; #pragma omp task depend (iterator (i = 0:32) : in : b[i*2:2]) ; @@ -89,3 +87,10 @@ f2 (void) #pragma omp ordered depend (iterator (int l = 0:2:3) : source) /* { dg-error "'iterator' modifier incompatible with 'source'" } */ } } + +void +f3 (void) +{ + #pragma omp task depend (iterator (i = 0:1): iterator (j = 0:1) : in : a) /* { dg-error "invalid depend kind|'iterator' undeclared|was not declared|expected '\\)' before ':' token" } */ + ; +} --- gcc/testsuite/c-c++-common/gomp/depobj-1.c.jj 2018-06-27 14:19:59.064026856 +0200 +++ gcc/testsuite/c-c++-common/gomp/depobj-1.c 2018-06-27 14:29:06.171462353 +0200 @@ -0,0 +1,62 @@ +typedef struct __attribute__((__aligned__ (sizeof (void *)))) omp_depend_t { + char __omp_depend_t__[2 * sizeof (void *)]; +} omp_depend_t; + +omp_depend_t bar (void); +extern const omp_depend_t cdepobj; +extern omp_depend_t depobj; +extern omp_depend_t depobja[4]; +extern omp_depend_t *pdepobj; +int a, b, i, j; + +void +f1 (void) +{ + #pragma omp depobj(depobj) depend(in : a) + #pragma omp depobj(depobj) update(inout) + #pragma omp task depend (depobj) + ; + #pragma omp depobj(depobj) destroy + #pragma omp task depend (iterator (i=1:3) : *(depobja + i)) + ; + #pragma omp depobj(pdepobj[0]) depend(mutexinoutset:a) + #pragma omp depobj(*pdepobj) destroy +} + +void +f2 (void) +{ + omp_depend_t depobjb[4]; + #pragma omp depobj /* { dg-error "expected" } */ + #pragma omp depobj destroy /* { dg-error "expected" } */ + #pragma omp depobj (depobj) /* { dg-error "expected 'depend', 'destroy' or 'update' clause" } */ + #pragma omp depobj (depobj) foobar /* { dg-error "expected 'depend', 'destroy' or 'update' clause" } */ + #pragma omp depobj(bar ()) update(inout) /* { dg-error "'depobj' expression is not lvalue expression" } */ + #pragma omp depobj (cdepobj) update(in) /* { dg-error "'const' qualified 'depobj' expression" } */ + #pragma omp depobj (depobjb) depend(in: a) /* { dg-error "type of 'depobj' expression is not 'omp_depend_t'" } */ + #pragma omp depobj (pdepobj) depend(in: a) /* { dg-error "type of 'depobj' expression is not 'omp_depend_t'" } */ + #pragma omp depobj (a) destroy /* { dg-error "type of 'depobj' expression is not 'omp_depend_t'" } */ + #pragma omp depobj (depobj) depend(a) /* { dg-error "does not have 'omp_depend_t' type in 'depend' clause without dependence type" } */ + #pragma omp depobj (depobj) update(foobar) /* { dg-error "expected 'in', 'out', 'inout' or 'mutexinoutset'" } */ + #pragma omp depobj (depobj) depend(in: *depobja) /* { dg-error "should not have 'omp_depend_t' type in 'depend' clause with dependence type" } */ + #pragma omp depobj (depobj) depend(in: a) depend(in: b) /* { dg-error "expected" } */ + #pragma omp depobj (depobj) depend(in: a) update(out) /* { dg-error "expected" } */ + #pragma omp depobj (depobj) depend(in: a, b) /* { dg-error "more than one locator in 'depend' clause on 'depobj' construct" } */ + #pragma omp depobj (depobj) depend(source) /* { dg-error "'depend\\(source\\)' is only allowed in 'omp ordered'" } */ + #pragma omp depobj (depobj) depend(sink: i + 1, j - 1) /* { dg-error "'depend\\(sink\\)' is only allowed in 'omp ordered'" } */ + #pragma omp depobj (depobj) depend(iterator (i = 0:2) : in : a) /* { dg-error "'iterator' modifier may not be specified on 'depobj' construct" } */ + if (0) + #pragma omp depobj (depobj) destroy /* { dg-error "'#pragma omp depobj' may only be used in compound statements" } */ + ; +} + +void +f3 (void) +{ + #pragma omp task depend (depobja[1:2]) /* { dg-error "'depend' clause without dependence type on array section" } */ + ; + #pragma omp task depend (a) /* { dg-error "'a' does not have 'omp_depend_t' type in 'depend' clause without dependence type" } */ + ; + #pragma omp task depend (in: depobj) /* { dg-error "'depobj' should not have 'omp_depend_t' type in 'depend' clause with dependence type" } */ + ; +} --- gcc/testsuite/g++.dg/gomp/depend-iterator-2.C.jj 2018-06-13 19:15:06.993378812 +0200 +++ gcc/testsuite/g++.dg/gomp/depend-iterator-2.C 2018-06-28 13:09:34.557143914 +0200 @@ -8,7 +8,7 @@ template <typename U, typename V, typena void f1 () { - #pragma omp task depend (iterator : in : a) // { dg-error "expected" } + #pragma omp task depend (iterator : in : a) // { dg-error "expected|invalid depend kind" } ; #pragma omp task depend (iterator (for = 0 : 2) : in : a) // { dg-error "expected" } ; @@ -26,9 +26,7 @@ f1 () ; #pragma omp task depend (iterator (i = N : 10 : 2, 3) : in : a) // { dg-error "expected" } ; - #pragma omp task depend (iterator (i = 0:1), iterator (j = 0:1) : in : a) // { dg-error "expected ':'|invalid depend kind" } - ; - #pragma omp task depend (iterator (i = 0:1): iterator (j = 0:1) : in : a) // { dg-error "invalid depend kind" } + #pragma omp task depend (iterator (i = 0:1), iterator (j = 0:1) : in : a) // { dg-error "expected ':'|invalid depend kind|was not declared|expected '\\)' before ':' token" } ; #pragma omp task depend (iterator (i = N:32) : in : b[i*2:2]) ; @@ -101,10 +99,19 @@ f3 () ; } +template <int N> void f4 () { + #pragma omp task depend (iterator (i = 0:1): iterator (j = 0:1) : in : a) // { dg-error "invalid depend kind|was not declared|expected '\\)' before ':' token" } + ; +} + +void +f5 () +{ f1 <struct S, float, int, 0> (); f2 <int, 1> (); f3 <struct S, float, int, 0, const int, const long long unsigned> (); + f4 <0> (); } --- gcc/testsuite/g++.dg/gomp/depobj-1.C.jj 2018-06-28 13:19:23.842611524 +0200 +++ gcc/testsuite/g++.dg/gomp/depobj-1.C 2018-06-28 14:43:21.164853650 +0200 @@ -0,0 +1,117 @@ +typedef struct __attribute__((__aligned__ (sizeof (void *)))) omp_depend_t { + char __omp_depend_t__[2 * sizeof (void *)]; +} omp_depend_t; + +omp_depend_t bar (void); +extern const omp_depend_t cdepobj; +extern omp_depend_t depobj, depobj4; +extern omp_depend_t depobja[4]; +extern omp_depend_t *pdepobj; +int a, b, i, j; + +template <int N> +void +f1 (bool x) +{ + #pragma omp depobj(x ? depobj : depobj4) depend(in : x ? a : b) + #pragma omp depobj(x ? depobj : depobj4) update(inout) + #pragma omp task depend (depobj) + ; + #pragma omp depobj(depobj) destroy + #pragma omp task depend (iterator (i=1:3) : *(depobja + i)) + ; + #pragma omp depobj(pdepobj[0]) depend(mutexinoutset:a) + #pragma omp depobj(*pdepobj) destroy +} + +template <typename T, typename T2> +void +f2 (T &depobj2, T2 depobj3, T *pdepobj) +{ + T depobj1; + T depobja[4]; + #pragma omp depobj(depobj1) depend(in : --a) + #pragma omp depobj(depobj1) update(inout) + #pragma omp task depend (depobj1) + ; + #pragma omp depobj(depobj1) destroy + #pragma omp depobj(depobj2) depend(in : a) + #pragma omp depobj(depobj2) update(inout) + #pragma omp task depend (depobj2) + ; + #pragma omp depobj(depobj2) destroy + #pragma omp depobj(depobj3) depend(in : a) + #pragma omp depobj(depobj3) update(inout) + #pragma omp task depend (depobj3) + ; + #pragma omp depobj(depobj3) destroy + for (int q = 1; q < 3; q++) + { + #pragma omp depobj(depobja[q]) depend (in:a) + } + #pragma omp task depend (iterator (i=1:3) : *(depobja + i)) + ; + for (int q = 1; q < 3; q++) + { + #pragma omp depobj(depobja[q]) destroy + } + #pragma omp depobj(pdepobj[0]) depend(mutexinoutset:a) + #pragma omp depobj(*pdepobj) destroy +} + +void +f3 (bool x) +{ + omp_depend_t depobjx, depobjy; + f1 <0> (x); + f2 <omp_depend_t, omp_depend_t &> (depobjx, depobjy, pdepobj); +} + +template <int N> +void +f4 (void) +{ + omp_depend_t depobjb[4]; + #pragma omp depobj // { dg-error "expected" } + #pragma omp depobj destroy // { dg-error "expected" } + #pragma omp depobj (depobj) // { dg-error "expected 'depend', 'destroy' or 'update' clause" } + #pragma omp depobj (depobj) foobar // { dg-error "expected 'depend', 'destroy' or 'update' clause" } + #pragma omp depobj(bar ()) update(inout) // { dg-error "'depobj' expression is not lvalue expression" } + #pragma omp depobj (cdepobj) update(in) // { dg-error "'const' qualified 'depobj' expression" } + #pragma omp depobj (depobjb) depend(in: a) // { dg-error "type of 'depobj' expression is not 'omp_depend_t'" } + #pragma omp depobj (pdepobj) depend(in: a) // { dg-error "type of 'depobj' expression is not 'omp_depend_t'" } + #pragma omp depobj (a) destroy // { dg-error "type of 'depobj' expression is not 'omp_depend_t'" } + #pragma omp depobj (depobj) depend(a) // { dg-error "does not have 'omp_depend_t' type in 'depend' clause without dependence type" } + #pragma omp depobj (depobj) update(foobar) // { dg-error "expected 'in', 'out', 'inout' or 'mutexinoutset'" } + #pragma omp depobj (depobj) depend(in: *depobja) // { dg-error "should not have 'omp_depend_t' type in 'depend' clause with dependence type" } + #pragma omp depobj (depobj) depend(in: a) depend(in: b) // { dg-error "expected" } + #pragma omp depobj (depobj) depend(in: a) update(out) // { dg-error "expected" } + #pragma omp depobj (depobj) depend(in: a, b) // { dg-error "more than one locator in 'depend' clause on 'depobj' construct" } + #pragma omp depobj (depobj) depend(source) // { dg-error "'depend\\(source\\)' is only allowed in 'omp ordered'" } + #pragma omp depobj (depobj) depend(sink: i + 1, j - 1) // { dg-error "'depend\\(sink\\)' is only allowed in 'omp ordered'" } + #pragma omp depobj (depobj) depend(iterator (i = 0:2) : in : a) // { dg-error "'iterator' modifier may not be specified on 'depobj' construct" } + if (0) + #pragma omp depobj (depobj) destroy // { dg-error "'#pragma omp depobj' may only be used in compound statements" } + ; +} + +template <int N> +void +f5 (void) +{ + #pragma omp task depend (depobja[1:2]) // { dg-error "'depend' clause without dependence type on array section" } + ; + #pragma omp task depend (a) // { dg-error "'a' does not have 'omp_depend_t' type in 'depend' clause without dependence type" } + ; + #pragma omp task depend (in: depobj) // { dg-error "'depobj' should not have 'omp_depend_t' type in 'depend' clause with dependence type" } + ; +} + +void +f6 (omp_depend_t &x) +{ + f4 <0> (); + f5 <0> (); + #pragma omp depobj (x) depend(in: a) + #pragma omp depobj (depobj) depend(in: x) // { dg-error "should not have 'omp_depend_t' type in 'depend' clause with dependence type" } +} --- include/gomp-constants.h.jj 2018-04-30 13:44:42.856561908 +0200 +++ include/gomp-constants.h 2018-06-26 11:46:40.877447868 +0200 @@ -251,6 +251,12 @@ enum gomp_map_kind at most and shifted by this many bits. */ #define GOMP_TARGET_ARG_VALUE_SHIFT 16 +/* Dependence types in omp_depend_t objects. */ +#define GOMP_DEPEND_IN 1 +#define GOMP_DEPEND_OUT 2 +#define GOMP_DEPEND_INOUT 3 +#define GOMP_DEPEND_MUTEXINOUTSET 4 + /* HSA specific data structures. */ /* Identifiers of device-specific target arguments. */ --- libgomp/omp.h.in.jj 2018-05-21 15:54:08.496902995 +0200 +++ libgomp/omp.h.in 2018-06-26 16:31:52.071327689 +0200 @@ -78,6 +78,11 @@ typedef enum omp_sync_hint_t typedef omp_sync_hint_t omp_lock_hint_t; +typedef struct __attribute__((__aligned__ (sizeof (void *)))) omp_depend_t +{ + char __omp_depend_t__[2 * sizeof (void *)]; +} omp_depend_t; + #ifdef __cplusplus extern "C" { # define __GOMP_NOTHROW throw () --- libgomp/task.c.jj 2018-06-18 19:02:46.486895948 +0200 +++ libgomp/task.c 2018-06-27 12:00:25.156146666 +0200 @@ -166,21 +166,72 @@ gomp_task_handle_depend (struct gomp_tas void **depend) { size_t ndepend = (uintptr_t) depend[0]; - size_t nout = (uintptr_t) depend[1]; size_t i; hash_entry_type ent; + if (ndepend) + { + /* depend[0] is total # */ + size_t nout = (uintptr_t) depend[1]; /* # of out: and inout: */ + /* ndepend - nout is # of in: */ + for (i = 0; i < ndepend; i++) + { + task->depend[i].addr = depend[2 + i]; + task->depend[i].is_in = i >= nout; + } + } + else + { + ndepend = (uintptr_t) depend[1]; /* total # */ + size_t nout = (uintptr_t) depend[2]; /* # of out: and inout: */ + size_t nmutexinoutset = (uintptr_t) depend[3]; /* # of mutexinoutset: */ + /* For now we treat mutexinoutset like out, which is compliant, but + inefficient. */ + size_t nin = (uintptr_t) depend[4]; /* # of in: */ + /* ndepend - nout - nmutexinoutset - nin is # of depobjs */ + size_t normal = nout + nmutexinoutset + nin; + size_t n = 0; + for (i = normal; i < ndepend; i++) + { + void **d = (void **) (uintptr_t) depend[5 + i]; + switch ((uintptr_t) d[1]) + { + case GOMP_DEPEND_OUT: + case GOMP_DEPEND_INOUT: + case GOMP_DEPEND_MUTEXINOUTSET: + break; + case GOMP_DEPEND_IN: + continue; + default: + gomp_fatal ("unknown omp_depend_t dependence type %d", + (int) (uintptr_t) d[1]); + } + task->depend[n].addr = d[0]; + task->depend[n++].is_in = 0; + } + for (i = 0; i < normal; i++) + { + task->depend[n].addr = depend[5 + i]; + task->depend[n++].is_in = i >= nout + nmutexinoutset; + } + for (i = normal; i < ndepend; i++) + { + void **d = (void **) (uintptr_t) depend[5 + i]; + if ((uintptr_t) d[1] != GOMP_DEPEND_IN) + continue; + task->depend[n].addr = d[0]; + task->depend[n++].is_in = 1; + } + } task->depend_count = ndepend; task->num_dependees = 0; if (parent->depend_hash == NULL) parent->depend_hash = htab_create (2 * ndepend > 12 ? 2 * ndepend : 12); for (i = 0; i < ndepend; i++) { - task->depend[i].addr = depend[2 + i]; task->depend[i].next = NULL; task->depend[i].prev = NULL; task->depend[i].task = task; - task->depend[i].is_in = i >= nout; task->depend[i].redundant = false; task->depend[i].redundant_out = false; @@ -205,7 +256,7 @@ gomp_task_handle_depend (struct gomp_tas last = ent; /* depend(in:...) doesn't depend on earlier depend(in:...). */ - if (i >= nout && ent->is_in) + if (task->depend[i].is_in && ent->is_in) continue; if (!ent->is_in) @@ -280,9 +331,18 @@ gomp_task_handle_depend (struct gomp_tas then the task may be executed by any member of the team. DEPEND is an array containing: + if depend[0] is non-zero, then: depend[0]: number of depend elements. - depend[1]: number of depend elements of type "out". - depend[2..N+1]: address of [1..N]th depend element. */ + depend[1]: number of depend elements of type "out/inout". + depend[2..N+1]: address of [1..N]th depend element. + otherwise, when depend[0] is zero, then: + depend[1]: number of depend elements. + depend[2]: number of depend elements of type "out/inout". + depend[3]: number of depend elements of type "mutexinoutset". + depend[4]: number of depend elements of type "in". + depend[5..4+depend[2]+depend[3]+depend[4]]: address of depend elements + depend[5+depend[2]+depend[3]+depend[4]..4+depend[1]]: address of + omp_depend_t objects. */ void GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *), @@ -377,7 +437,7 @@ GOMP_task (void (*fn) (void *), void *da size_t depend_size = 0; if (flags & GOMP_TASK_FLAG_DEPEND) - depend_size = ((uintptr_t) depend[0] + depend_size = ((uintptr_t) (depend[0] ? depend[0] : depend[1]) * sizeof (struct gomp_task_depend_entry)); task = gomp_malloc (sizeof (*task) + depend_size + arg_size + arg_align - 1); @@ -617,7 +677,7 @@ gomp_create_target_task (struct gomp_dev if (depend != NULL) { - depend_cnt = (uintptr_t) depend[0]; + depend_cnt = (uintptr_t) (depend[0] ? depend[0] : depend[1]); depend_size = depend_cnt * sizeof (struct gomp_task_depend_entry); } if (fn) @@ -1496,21 +1556,50 @@ gomp_task_maybe_wait_for_dependencies (v struct gomp_team *team = thr->ts.team; struct gomp_task_depend_entry elem, *ent = NULL; struct gomp_taskwait taskwait; - size_t ndepend = (uintptr_t) depend[0]; + size_t orig_ndepend = (uintptr_t) depend[0]; size_t nout = (uintptr_t) depend[1]; + size_t ndepend = orig_ndepend; + size_t normal = ndepend; + size_t n = 2; size_t i; size_t num_awaited = 0; struct gomp_task *child_task = NULL; struct gomp_task *to_free = NULL; int do_wake = 0; + if (ndepend == 0) + { + ndepend = nout; + nout = (uintptr_t) depend[2] + (uintptr_t) depend[3]; + normal = nout + (uintptr_t) depend[4]; + n = 5; + } gomp_mutex_lock (&team->task_lock); for (i = 0; i < ndepend; i++) { - elem.addr = depend[i + 2]; + elem.addr = depend[i + n]; + elem.is_in = i >= nout; + if (__builtin_expect (i >= normal, 0)) + { + void **d = (void **) elem.addr; + switch ((uintptr_t) d[1]) + { + case GOMP_DEPEND_IN: + break; + case GOMP_DEPEND_OUT: + case GOMP_DEPEND_INOUT: + case GOMP_DEPEND_MUTEXINOUTSET: + elem.is_in = 0; + break; + default: + gomp_fatal ("unknown omp_depend_t dependence type %d", + (int) (uintptr_t) d[1]); + } + elem.addr = d[0]; + } ent = htab_find (task->depend_hash, &elem); for (; ent; ent = ent->next) - if (i >= nout && ent->is_in) + if (elem.is_in && ent->is_in) continue; else { --- libgomp/testsuite/libgomp.c-c++-common/depend-iterator-2.c.jj 2018-06-27 11:50:37.190730353 +0200 +++ libgomp/testsuite/libgomp.c-c++-common/depend-iterator-2.c 2018-06-27 11:45:24.525508965 +0200 @@ -0,0 +1,63 @@ +volatile int v; + +__attribute__((noipa)) void +foo (int *p, int i) +{ + #pragma omp task depend (out: p[0]) + v++; + #pragma omp task depend (in: p[0]) + v++; + #pragma omp task depend (inout: p[0]) + v++; + #pragma omp task depend (mutexinoutset: p[0]) + v++; + #pragma omp task depend (out: p[0]) depend (in: p[1]) + v++; + #pragma omp task depend (in: p[0]) depend (inout: p[1]) + v++; + #pragma omp task depend (inout: p[0]) depend (mutexinoutset: p[1]) + v++; + #pragma omp task depend (mutexinoutset: p[0]) depend (out: p[1]) + v++; + #pragma omp task depend (iterator (j=0:2) : out : p[j]) + v++; + #pragma omp task depend (iterator (j=0:2) : in : p[j]) + v++; + #pragma omp task depend (iterator (j=0:2) : inout : p[j]) + v++; + #pragma omp task depend (iterator (j=0:2) : mutexinoutset : p[j]) + v++; + #pragma omp task depend (iterator (j=0:2) : out : p[j]) depend (iterator (j=0:2) : in : p[j + 2]) + v++; + #pragma omp task depend (iterator (j=0:2) : in : p[j]) depend (iterator (j=0:2) : inout : p[j + 2]) + v++; + #pragma omp task depend (iterator (j=0:2) : inout : p[j]) depend (iterator (j=0:2) : mutexinoutset : p[j + 2]) + v++; + #pragma omp task depend (iterator (j=0:2) : mutexinoutset : p[j]) depend (iterator (j=0:2) : out : p[j + 2]) + v++; + #pragma omp task depend (iterator (j=0:i) : out : p[j]) + v++; + #pragma omp task depend (iterator (j=0:i) : in : p[j]) + v++; + #pragma omp task depend (iterator (j=0:i) : inout : p[j]) + v++; + #pragma omp task depend (iterator (j=0:i) : mutexinoutset : p[j]) + v++; + #pragma omp task depend (iterator (j=0:i) : out : p[j]) depend (iterator (j=0:i) : in : p[j + 2]) + v++; + #pragma omp task depend (iterator (j=0:i) : in : p[j]) depend (iterator (j=0:i) : inout : p[j + 2]) + v++; + #pragma omp task depend (iterator (j=0:i) : inout : p[j]) depend (iterator (j=0:i) : mutexinoutset : p[j + 2]) + v++; + #pragma omp task depend (iterator (j=0:i) : mutexinoutset : p[j]) depend (iterator (j=0:i) : out : p[j + 2]) + v++; +} + +int +main () +{ + int p[4]; + foo (p, 2); + foo (p, -1); + return 0; +} --- libgomp/testsuite/libgomp.c-c++-common/depobj-1.c.jj 2018-06-27 15:31:43.275513633 +0200 +++ libgomp/testsuite/libgomp.c-c++-common/depobj-1.c 2018-06-27 15:47:09.637231807 +0200 @@ -0,0 +1,99 @@ +#include <stdlib.h> +#include <omp.h> + +void +dep (void) +{ + int x = 1; + omp_depend_t d1, d2; + #pragma omp depobj (d1) depend(in: x) + #pragma omp depobj (d2) depend(in: x) + #pragma omp depobj (d2) update(out) + #pragma omp parallel + #pragma omp single + { + #pragma omp task shared (x) depend(d2) + x = 2; + #pragma omp task shared (x) depend(d1) + if (x != 2) + abort (); + } + #pragma omp depobj (d2) destroy + #pragma omp depobj (d1) destroy +} + +void +dep2 (void) +{ + #pragma omp parallel + #pragma omp single + { + int x = 1; + omp_depend_t d1, d2; + #pragma omp depobj (d1) depend(out: x) + #pragma omp depobj (*&d2) depend (in:x) + #pragma omp depobj(d2)update(in) + #pragma omp task shared (x) depend(d1) + x = 2; + #pragma omp task shared (x) depend(d2) + if (x != 2) + abort (); + #pragma omp taskwait + #pragma omp depobj(d1)destroy + #pragma omp depobj((&d2)[0]) destroy + } +} + +void +dep3 (void) +{ + omp_depend_t d[2]; + #pragma omp parallel + { + int x = 1; + #pragma omp single + { + #pragma omp depobj(d[0]) depend(out:x) + #pragma omp depobj(d[1]) depend(in: x) + #pragma omp task shared (x) depend(*d) + x = 2; + #pragma omp task shared (x) depend(*(d + 1)) + if (x != 2) + abort (); + } + } + #pragma omp depobj(d[0]) destroy + #pragma omp depobj(d[1]) destroy +} + +int xx; +omp_depend_t dd1, dd2; + +void +antidep (void) +{ + xx = 1; + #pragma omp parallel + #pragma omp single + { + #pragma omp task shared(xx) depend(dd2) + if (xx != 1) + abort (); + #pragma omp task shared(xx) depend(dd1) + xx = 2; + } +} + +int +main () +{ + dep (); + dep2 (); + dep3 (); + #pragma omp depobj (dd1) depend (inout: xx) + #pragma omp depobj (dd2) depend (in : xx) + antidep (); + #pragma omp depobj (dd2) destroy + #pragma omp depobj (dd1) destroy + return 0; +} --- libgomp/testsuite/libgomp.c++/depend-1.C.jj 2018-06-28 15:25:19.944964463 +0200 +++ libgomp/testsuite/libgomp.c++/depend-1.C 2018-06-28 15:25:14.145959638 +0200 @@ -0,0 +1,31 @@ +extern "C" void abort (); +int a, b, c, d, e; + +void +foo (int &x, bool y) +{ + #pragma omp task depend (out: x) + a = 1; + #pragma omp task depend (out: y ? b : c) + (y ? b : c) = 2; + #pragma omp task depend (inout: --d) + d += 4; + #pragma omp task depend (in : a, (y ? b : c), d) + e = a + b * 10 + c * 100 + d * 1000; +} + +int +main () +{ + #pragma omp parallel + #pragma omp single + foo (a, true); + if (e != 1 + 20 + 0 + 3000) + abort (); + a = b = c = d = e = 0; + #pragma omp parallel + #pragma omp single + foo (a, false); + if (e != 1 + 0 + 200 + 3000) + abort (); +} --- libgomp/testsuite/libgomp.c++/depobj-1.C.jj 2018-06-28 15:29:20.598164497 +0200 +++ libgomp/testsuite/libgomp.c++/depobj-1.C 2018-06-28 15:38:44.035632853 +0200 @@ -0,0 +1,103 @@ +#include <stdlib.h> +#include <omp.h> + +void +dep (omp_depend_t &d1, omp_depend_t *d2) +{ + int x = 1; + #pragma omp depobj (d1) depend(in: x) + #pragma omp depobj (*d2) depend(in: x) + + #pragma omp depobj (d2[0]) update(out) + #pragma omp parallel + #pragma omp single + { + #pragma omp task shared (x) depend(*d2) + x = 2; + #pragma omp task shared (x) depend(d1) + if (x != 2) + abort (); + } + #pragma omp depobj (d2[0]) destroy + #pragma omp depobj (d1) destroy +} + +template <typename T> +void +dep2 (T &d2) +{ + T d1; + #pragma omp parallel + #pragma omp single + { + int x = 1; + #pragma omp depobj (d1) depend(out: x) + #pragma omp depobj (*&d2) depend (in:x) + #pragma omp depobj(d2)update(in) + #pragma omp task shared (x) depend(d1) + x = 2; + #pragma omp task shared (x) depend(d2) + if (x != 2) + abort (); + #pragma omp taskwait + #pragma omp depobj(d1)destroy + #pragma omp depobj((&d2)[0]) destroy + } +} + +template <typename T> +void +dep3 (void) +{ + T d[2]; + #pragma omp parallel + { + int x = 1; + #pragma omp single + { + #pragma omp depobj(d[0]) depend(out:x) + #pragma omp depobj(d[1]) depend(in: x) + #pragma omp task shared (x) depend(*d) + x = 2; + #pragma omp task shared (x) depend(*(d + 1)) + if (x != 2) + abort (); + } + } + #pragma omp depobj(d[0]) destroy + #pragma omp depobj(d[1]) destroy +} + +int xx; +omp_depend_t dd1, dd2; + +template <int N> +void +antidep (void) +{ + xx = 1; + #pragma omp parallel + #pragma omp single + { + #pragma omp task shared(xx) depend(dd2) + if (xx != 1) + abort (); + #pragma omp task shared(xx) depend(dd1) + xx = 2; + } +} + +int +main () +{ + omp_depend_t d1, d2, d3; + dep (d1, &d2); + dep2 <omp_depend_t> (d3); + dep3 <omp_depend_t> (); + #pragma omp depobj (dd1) depend (inout: xx) + #pragma omp depobj (dd2) depend (in : xx) + antidep <0> (); + #pragma omp depobj (dd2) destroy + #pragma omp depobj (dd1) destroy + return 0; +} Jakub