From 6c7ae8c56f9341f180e097d5eb7ba05cb8eec413 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 24 May 2019 23:31:59 +0200 Subject: [PATCH] tree-core.h (enum omp_clause_code): Add OMP_CLAUSE__CONDTEMP_. * tree-core.h (enum omp_clause_code): Add OMP_CLAUSE__CONDTEMP_. * tree.h (OMP_CLAUSE_DECL): Use OMP_CLAUSE__CONDTEMP_ instead of OMP_CLAUSE__REDUCTEMP_. * tree.c (omp_clause_num_ops, omp_clause_code_name): Add OMP_CLAUSE__CONDTEMP_. (walk_tree_1): Handle OMP_CLAUSE__CONDTEMP_. * tree-pretty-print.c (dump_omp_clause): Likewise. * tree-nested.c (convert_nonlocal_omp_clauses, convert_local_omp_clauses): Likewise. * gimplify.c (enum gimplify_omp_var_data): Use hexadecimal constants instead of decimal. Add GOVD_LASTPRIVATE_CONDITIONAL. (gimplify_scan_omp_clauses): Don't reject lastprivate conditional on OMP_FOR. (gimplify_omp_for): Warn and disable conditional modifier from lastprivate on loop iterators. * omp-general.h (struct omp_for_data): Add lastprivate_conditional member. * omp-general.c (omp_extract_for_data): Initialize it. * omp-low.c (struct omp_context): Add lastprivate_conditional_map member. (delete_omp_context): Delete it. (lower_lastprivate_conditional_clauses): New function. (lower_lastprivate_clauses): Add BODY_P and CSTMT_LIST arguments, handle lastprivate conditional clauses. (lower_reduction_clauses): Add CLIST argument, emit it into the critical section if any. (lower_omp_sections): Adjust lower_lastprivate_clauses and lower_reduction_clauses callers. (lower_omp_for_lastprivate): Add CLIST argument, pass it through to lower_lastprivate_clauses. (lower_omp_for): Call lower_lastprivate_conditional_clauses, adjust lower_omp_for_lastprivate and lower_reduction_clauses callers, emit clist into a critical section if not emitted there already by lower_reduction_clauses. (lower_omp_taskreg, lower_omp_teams): Adjust lower_reduction_clauses callers. (lower_omp_1): Handle GIMPLE_ASSIGNs storing into lastprivate conditional variables. * omp-expand.c (determine_parallel_type): Punt if OMP_CLAUSE__CONDTEMP_ clause is present. (expand_omp_for_generic, expand_omp_for_static_nochunk, expand_omp_for_static_chunk): Handle lastprivate conditional. (expand_omp_for): Handle fd.lastprivate_conditional like fd.have_reductemp. gcc/testsuite/ * c-c++-common/gomp/lastprivate-conditional-2.c (foo): Don't expect sorry for omp for. * c-c++-common/gomp/lastprivate-conditional-3.c: New test. libgomp/ * testsuite/libgomp.c-c++-common/lastprivate-conditional-1.c: New test. * testsuite/libgomp.c-c++-common/lastprivate-conditional-2.c: New test. From-SVN: r271610 --- gcc/ChangeLog | 47 ++++ gcc/gimplify.c | 99 +++++-- gcc/omp-expand.c | 300 ++++++++++++++++++--- gcc/omp-general.c | 6 + gcc/omp-general.h | 1 + gcc/omp-low.c | 188 +++++++++++-- gcc/testsuite/ChangeLog | 6 + .../c-c++-common/gomp/lastprivate-conditional-2.c | 2 +- .../c-c++-common/gomp/lastprivate-conditional-3.c | 26 ++ gcc/tree-core.h | 3 + gcc/tree-nested.c | 2 + gcc/tree-pretty-print.c | 3 + gcc/tree.c | 3 + gcc/tree.h | 2 +- libgomp/ChangeLog | 3 + .../lastprivate-conditional-1.c | 144 ++++++++++ .../lastprivate-conditional-2.c | 171 ++++++++++++ 17 files changed, 915 insertions(+), 91 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/gomp/lastprivate-conditional-3.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/lastprivate-conditional-1.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/lastprivate-conditional-2.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e340675a2cf..93ba0f23592 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,50 @@ +2019-05-24 Jakub Jelinek + + * tree-core.h (enum omp_clause_code): Add OMP_CLAUSE__CONDTEMP_. + * tree.h (OMP_CLAUSE_DECL): Use OMP_CLAUSE__CONDTEMP_ instead of + OMP_CLAUSE__REDUCTEMP_. + * tree.c (omp_clause_num_ops, omp_clause_code_name): Add + OMP_CLAUSE__CONDTEMP_. + (walk_tree_1): Handle OMP_CLAUSE__CONDTEMP_. + * tree-pretty-print.c (dump_omp_clause): Likewise. + * tree-nested.c (convert_nonlocal_omp_clauses, + convert_local_omp_clauses): Likewise. + * gimplify.c (enum gimplify_omp_var_data): Use hexadecimal constants + instead of decimal. Add GOVD_LASTPRIVATE_CONDITIONAL. + (gimplify_scan_omp_clauses): Don't reject lastprivate conditional + on OMP_FOR. + (gimplify_omp_for): Warn and disable conditional modifier from + lastprivate on loop iterators. + * omp-general.h (struct omp_for_data): Add lastprivate_conditional + member. + * omp-general.c (omp_extract_for_data): Initialize it. + * omp-low.c (struct omp_context): Add lastprivate_conditional_map + member. + (delete_omp_context): Delete it. + (lower_lastprivate_conditional_clauses): New function. + (lower_lastprivate_clauses): Add BODY_P and CSTMT_LIST arguments, + handle lastprivate conditional clauses. + (lower_reduction_clauses): Add CLIST argument, emit it into + the critical section if any. + (lower_omp_sections): Adjust lower_lastprivate_clauses and + lower_reduction_clauses callers. + (lower_omp_for_lastprivate): Add CLIST argument, pass it through + to lower_lastprivate_clauses. + (lower_omp_for): Call lower_lastprivate_conditional_clauses, adjust + lower_omp_for_lastprivate and lower_reduction_clauses callers, emit + clist into a critical section if not emitted there already by + lower_reduction_clauses. + (lower_omp_taskreg, lower_omp_teams): Adjust lower_reduction_clauses + callers. + (lower_omp_1): Handle GIMPLE_ASSIGNs storing into lastprivate + conditional variables. + * omp-expand.c (determine_parallel_type): Punt if OMP_CLAUSE__CONDTEMP_ + clause is present. + (expand_omp_for_generic, expand_omp_for_static_nochunk, + expand_omp_for_static_chunk): Handle lastprivate conditional. + (expand_omp_for): Handle fd.lastprivate_conditional like + fd.have_reductemp. + 2019-05-24 Andrew Stubbs * config/gcn/gcn-run.c (main): Set a non-zero return value if the diff --git a/gcc/gimplify.c b/gcc/gimplify.c index e5713dd4e8c..b8b7e803990 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -71,47 +71,50 @@ static hash_set *asan_poisoned_variables = NULL; enum gimplify_omp_var_data { - GOVD_SEEN = 1, - GOVD_EXPLICIT = 2, - GOVD_SHARED = 4, - GOVD_PRIVATE = 8, - GOVD_FIRSTPRIVATE = 16, - GOVD_LASTPRIVATE = 32, - GOVD_REDUCTION = 64, - GOVD_LOCAL = 128, - GOVD_MAP = 256, - GOVD_DEBUG_PRIVATE = 512, - GOVD_PRIVATE_OUTER_REF = 1024, - GOVD_LINEAR = 2048, - GOVD_ALIGNED = 4096, + GOVD_SEEN = 0x000001, + GOVD_EXPLICIT = 0x000002, + GOVD_SHARED = 0x000004, + GOVD_PRIVATE = 0x000008, + GOVD_FIRSTPRIVATE = 0x000010, + GOVD_LASTPRIVATE = 0x000020, + GOVD_REDUCTION = 0x000040, + GOVD_LOCAL = 0x00080, + GOVD_MAP = 0x000100, + GOVD_DEBUG_PRIVATE = 0x000200, + GOVD_PRIVATE_OUTER_REF = 0x000400, + GOVD_LINEAR = 0x000800, + GOVD_ALIGNED = 0x001000, /* Flag for GOVD_MAP: don't copy back. */ - GOVD_MAP_TO_ONLY = 8192, + GOVD_MAP_TO_ONLY = 0x002000, /* Flag for GOVD_LINEAR or GOVD_LASTPRIVATE: no outer reference. */ - GOVD_LINEAR_LASTPRIVATE_NO_OUTER = 16384, + GOVD_LINEAR_LASTPRIVATE_NO_OUTER = 0x004000, - GOVD_MAP_0LEN_ARRAY = 32768, + GOVD_MAP_0LEN_ARRAY = 0x008000, /* Flag for GOVD_MAP, if it is always, to or always, tofrom mapping. */ - GOVD_MAP_ALWAYS_TO = 65536, + GOVD_MAP_ALWAYS_TO = 0x010000, /* Flag for shared vars that are or might be stored to in the region. */ - GOVD_WRITTEN = 131072, + GOVD_WRITTEN = 0x020000, /* Flag for GOVD_MAP, if it is a forced mapping. */ - GOVD_MAP_FORCE = 262144, + GOVD_MAP_FORCE = 0x040000, /* Flag for GOVD_MAP: must be present already. */ - GOVD_MAP_FORCE_PRESENT = 524288, + GOVD_MAP_FORCE_PRESENT = 0x080000, /* Flag for GOVD_MAP: only allocate. */ - GOVD_MAP_ALLOC_ONLY = 1048576, + GOVD_MAP_ALLOC_ONLY = 0x100000, /* Flag for GOVD_MAP: only copy back. */ - GOVD_MAP_FROM_ONLY = 2097152, + GOVD_MAP_FROM_ONLY = 0x200000, - GOVD_NONTEMPORAL = 4194304, + GOVD_NONTEMPORAL = 0x400000, + + /* Flag for GOVD_LASTPRIVATE: conditional modifier. */ + GOVD_LASTPRIVATE_CONDITIONAL = 0x800000, GOVD_DATA_SHARE_CLASS = (GOVD_SHARED | GOVD_PRIVATE | GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LINEAR @@ -8139,9 +8142,17 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c) = 0; } if (OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c)) - sorry_at (OMP_CLAUSE_LOCATION (c), - "% modifier on % clause " - "not supported yet"); + { + if (code == OMP_FOR) + flags |= GOVD_LASTPRIVATE_CONDITIONAL; + else + { + sorry_at (OMP_CLAUSE_LOCATION (c), + "% modifier on % " + "clause not supported yet"); + OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c) = 0; + } + } if (outer_ctx && (outer_ctx->region_type == ORT_COMBINED_PARALLEL || ((outer_ctx->region_type & ORT_COMBINED_TEAMS) @@ -10770,7 +10781,22 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) 1 + (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) != 1)); if (n != NULL && (n->value & GOVD_DATA_SHARE_CLASS) != 0) - omp_notice_variable (gimplify_omp_ctxp, decl, true); + { + omp_notice_variable (gimplify_omp_ctxp, decl, true); + if (n->value & GOVD_LASTPRIVATE_CONDITIONAL) + for (tree c3 = omp_find_clause (OMP_FOR_CLAUSES (for_stmt), + OMP_CLAUSE_LASTPRIVATE); + c3; c3 = omp_find_clause (OMP_CLAUSE_CHAIN (c3), + OMP_CLAUSE_LASTPRIVATE)) + if (OMP_CLAUSE_DECL (c3) == decl) + { + warning_at (OMP_CLAUSE_LOCATION (c3), 0, + "conditional % on loop " + "iterator %qD ignored", decl); + OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c3) = 0; + n->value &= ~GOVD_LASTPRIVATE_CONDITIONAL; + } + } else if (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) == 1) { c = build_omp_clause (input_location, OMP_CLAUSE_LINEAR); @@ -11005,7 +11031,24 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) } } else if (omp_is_private (gimplify_omp_ctxp, decl, 0)) - omp_notice_variable (gimplify_omp_ctxp, decl, true); + { + omp_notice_variable (gimplify_omp_ctxp, decl, true); + splay_tree_node n = splay_tree_lookup (gimplify_omp_ctxp->variables, + (splay_tree_key) decl); + if (n && (n->value & GOVD_LASTPRIVATE_CONDITIONAL)) + for (tree c3 = omp_find_clause (OMP_FOR_CLAUSES (for_stmt), + OMP_CLAUSE_LASTPRIVATE); + c3; c3 = omp_find_clause (OMP_CLAUSE_CHAIN (c3), + OMP_CLAUSE_LASTPRIVATE)) + if (OMP_CLAUSE_DECL (c3) == decl) + { + warning_at (OMP_CLAUSE_LOCATION (c3), 0, + "conditional % on loop " + "iterator %qD ignored", decl); + OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c3) = 0; + n->value &= ~GOVD_LASTPRIVATE_CONDITIONAL; + } + } else omp_add_variable (gimplify_omp_ctxp, decl, GOVD_PRIVATE | GOVD_SEEN); diff --git a/gcc/omp-expand.c b/gcc/omp-expand.c index 0d7f104a2f2..dfac4b075e5 100644 --- a/gcc/omp-expand.c +++ b/gcc/omp-expand.c @@ -345,7 +345,8 @@ determine_parallel_type (struct omp_region *region) || ((OMP_CLAUSE_SCHEDULE_KIND (c) & OMP_CLAUSE_SCHEDULE_MASK) == OMP_CLAUSE_SCHEDULE_STATIC) || omp_find_clause (clauses, OMP_CLAUSE_ORDERED) - || omp_find_clause (clauses, OMP_CLAUSE__REDUCTEMP_)) + || omp_find_clause (clauses, OMP_CLAUSE__REDUCTEMP_) + || omp_find_clause (clauses, OMP_CLAUSE__CONDTEMP_)) return; } else if (region->inner->type == GIMPLE_OMP_SECTIONS @@ -2679,16 +2680,17 @@ expand_omp_for_generic (struct omp_region *region, gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR); if (fd->ordered - && omp_find_clause (gimple_omp_for_clauses (gsi_stmt (gsi)), + && omp_find_clause (gimple_omp_for_clauses (fd->for_stmt), OMP_CLAUSE_LASTPRIVATE)) ordered_lastprivate = false; tree reductions = NULL_TREE; - tree mem = NULL_TREE; + tree mem = NULL_TREE, cond_var = NULL_TREE, condtemp = NULL_TREE; + tree memv = NULL_TREE; if (sched_arg) { if (fd->have_reductemp) { - tree c = omp_find_clause (gimple_omp_for_clauses (gsi_stmt (gsi)), + tree c = omp_find_clause (gimple_omp_for_clauses (fd->for_stmt), OMP_CLAUSE__REDUCTEMP_); reductions = OMP_CLAUSE_DECL (c); gcc_assert (TREE_CODE (reductions) == SSA_NAME); @@ -2703,8 +2705,25 @@ expand_omp_for_generic (struct omp_region *region, } else reductions = null_pointer_node; - /* For now. */ - mem = null_pointer_node; + if (fd->lastprivate_conditional) + { + tree c = omp_find_clause (gimple_omp_for_clauses (fd->for_stmt), + OMP_CLAUSE__CONDTEMP_); + condtemp = OMP_CLAUSE_DECL (c); + c = omp_find_clause (OMP_CLAUSE_CHAIN (c), OMP_CLAUSE__CONDTEMP_); + cond_var = OMP_CLAUSE_DECL (c); + tree type = TREE_TYPE (condtemp); + memv = create_tmp_var (type); + TREE_ADDRESSABLE (memv) = 1; + unsigned HOST_WIDE_INT sz + = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (type))); + sz *= fd->lastprivate_conditional; + expand_omp_build_assign (&gsi, memv, build_int_cst (type, sz), + false); + mem = build_fold_addr_expr (memv); + } + else + mem = null_pointer_node; } if (fd->collapse > 1 || fd->ordered) { @@ -2959,6 +2978,8 @@ expand_omp_for_generic (struct omp_region *region, gsi_insert_before (&gsi, gimple_build_assign (arr, clobber), GSI_SAME_STMT); } + if (fd->lastprivate_conditional) + expand_omp_build_assign (&gsi, condtemp, memv, false); if (fd->have_reductemp) { gimple *g = gsi_stmt (gsi); @@ -3029,6 +3050,35 @@ expand_omp_for_generic (struct omp_region *region, NULL_TREE, false, GSI_CONTINUE_LINKING); assign_stmt = gimple_build_assign (startvar, t); gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING); + if (cond_var) + { + tree itype = TREE_TYPE (cond_var); + /* For lastprivate(conditional:) itervar, we need some iteration + counter that starts at unsigned non-zero and increases. + Prefer as few IVs as possible, so if we can use startvar + itself, use that, or startvar + constant (those would be + incremented with step), and as last resort use the s0 + 1 + incremented by 1. */ + if ((fd->ordered && fd->collapse == 1) + || bias + || POINTER_TYPE_P (type) + || TREE_CODE (fd->loop.n1) != INTEGER_CST + || fd->loop.cond_code != LT_EXPR) + t = fold_build2 (PLUS_EXPR, itype, fold_convert (itype, istart0), + build_int_cst (itype, 1)); + else if (tree_int_cst_sgn (fd->loop.n1) == 1) + t = fold_convert (itype, t); + else + { + tree c = fold_convert (itype, fd->loop.n1); + c = fold_build2 (MINUS_EXPR, itype, build_int_cst (itype, 1), c); + t = fold_build2 (PLUS_EXPR, itype, fold_convert (itype, t), c); + } + t = force_gimple_operand_gsi (&gsi, t, false, + NULL_TREE, false, GSI_CONTINUE_LINKING); + assign_stmt = gimple_build_assign (cond_var, t); + gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING); + } t = iend0; if (fd->ordered && fd->collapse == 1) @@ -3213,6 +3263,25 @@ expand_omp_for_generic (struct omp_region *region, assign_stmt = gimple_build_assign (vback, t); gsi_insert_before (&gsi, assign_stmt, GSI_SAME_STMT); + if (cond_var) + { + tree itype = TREE_TYPE (cond_var); + tree t2; + if ((fd->ordered && fd->collapse == 1) + || bias + || POINTER_TYPE_P (type) + || TREE_CODE (fd->loop.n1) != INTEGER_CST + || fd->loop.cond_code != LT_EXPR) + t2 = build_int_cst (itype, 1); + else + t2 = fold_convert (itype, fd->loop.step); + t2 = fold_build2 (PLUS_EXPR, itype, cond_var, t2); + t2 = force_gimple_operand_gsi (&gsi, t2, false, + NULL_TREE, true, GSI_SAME_STMT); + assign_stmt = gimple_build_assign (cond_var, t2); + gsi_insert_before (&gsi, assign_stmt, GSI_SAME_STMT); + } + if (fd->ordered && counts[fd->collapse - 1] == NULL_TREE) { tree tem; @@ -3465,12 +3534,13 @@ expand_omp_for_static_nochunk (struct omp_region *region, basic_block entry_bb, second_bb, third_bb, exit_bb, seq_start_bb; basic_block body_bb, cont_bb, collapse_bb = NULL; basic_block fin_bb; - gimple_stmt_iterator gsi; + gimple_stmt_iterator gsi, gsip; edge ep; bool broken_loop = region->cont == NULL; tree *counts = NULL; tree n1, n2, step; tree reductions = NULL_TREE; + tree cond_var = NULL_TREE; itype = type = TREE_TYPE (fd->loop.v); if (POINTER_TYPE_P (type)) @@ -3495,6 +3565,8 @@ expand_omp_for_static_nochunk (struct omp_region *region, /* Iteration space partitioning goes in ENTRY_BB. */ gsi = gsi_last_nondebug_bb (entry_bb); gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR); + gsip = gsi; + gsi_prev (&gsip); if (fd->collapse > 1) { @@ -3524,7 +3596,7 @@ expand_omp_for_static_nochunk (struct omp_region *region, n2 = force_gimple_operand_gsi (&gsi, n2, true, NULL_TREE, true, GSI_SAME_STMT); gcond *cond_stmt = gimple_build_cond (fd->loop.cond_code, n1, n2, - NULL_TREE, NULL_TREE); + NULL_TREE, NULL_TREE); gsi_insert_before (&gsi, cond_stmt, GSI_SAME_STMT); if (walk_tree (gimple_cond_lhs_ptr (cond_stmt), expand_omp_regimplify_p, NULL, NULL) @@ -3554,28 +3626,64 @@ expand_omp_for_static_nochunk (struct omp_region *region, gsi = gsi_last_bb (entry_bb); } - if (fd->have_reductemp) + if (fd->have_reductemp || fd->lastprivate_conditional) { tree t1 = build_int_cst (long_integer_type_node, 0); tree t2 = build_int_cst (long_integer_type_node, 1); tree t3 = build_int_cstu (long_integer_type_node, (HOST_WIDE_INT_1U << 31) + 1); tree clauses = gimple_omp_for_clauses (fd->for_stmt); - clauses = omp_find_clause (clauses, OMP_CLAUSE__REDUCTEMP_); - reductions = OMP_CLAUSE_DECL (clauses); - gcc_assert (TREE_CODE (reductions) == SSA_NAME); - gimple *g = SSA_NAME_DEF_STMT (reductions); - reductions = gimple_assign_rhs1 (g); - OMP_CLAUSE_DECL (clauses) = reductions; - gimple_stmt_iterator gsi2 = gsi_for_stmt (g); + gimple_stmt_iterator gsi2 = gsi_none (); + gimple *g = NULL; + tree mem = null_pointer_node, memv = NULL_TREE; + tree condtemp = NULL_TREE; + if (fd->have_reductemp) + { + tree c = omp_find_clause (clauses, OMP_CLAUSE__REDUCTEMP_); + reductions = OMP_CLAUSE_DECL (c); + gcc_assert (TREE_CODE (reductions) == SSA_NAME); + g = SSA_NAME_DEF_STMT (reductions); + reductions = gimple_assign_rhs1 (g); + OMP_CLAUSE_DECL (c) = reductions; + gsi2 = gsi_for_stmt (g); + } + else + { + if (gsi_end_p (gsip)) + gsi2 = gsi_after_labels (region->entry); + else + gsi2 = gsip; + reductions = null_pointer_node; + } + if (fd->lastprivate_conditional) + { + tree c = omp_find_clause (clauses, OMP_CLAUSE__CONDTEMP_); + condtemp = OMP_CLAUSE_DECL (c); + c = omp_find_clause (OMP_CLAUSE_CHAIN (c), OMP_CLAUSE__CONDTEMP_); + cond_var = OMP_CLAUSE_DECL (c); + tree type = TREE_TYPE (condtemp); + memv = create_tmp_var (type); + TREE_ADDRESSABLE (memv) = 1; + unsigned HOST_WIDE_INT sz + = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (type))); + sz *= fd->lastprivate_conditional; + expand_omp_build_assign (&gsi2, memv, build_int_cst (type, sz), + false); + mem = build_fold_addr_expr (memv); + } tree t = build_call_expr (builtin_decl_explicit (BUILT_IN_GOMP_LOOP_START), 9, t1, t2, t2, t3, t1, null_pointer_node, - null_pointer_node, reductions, null_pointer_node); + null_pointer_node, reductions, mem); force_gimple_operand_gsi (&gsi2, t, true, NULL_TREE, true, GSI_SAME_STMT); - gsi_remove (&gsi2, true); - release_ssa_name (gimple_assign_lhs (g)); + if (fd->lastprivate_conditional) + expand_omp_build_assign (&gsi2, condtemp, memv, false); + if (fd->have_reductemp) + { + gsi_remove (&gsi2, true); + release_ssa_name (gimple_assign_lhs (g)); + } } switch (gimple_omp_for_kind (fd->for_stmt)) { @@ -3735,6 +3843,33 @@ expand_omp_for_static_nochunk (struct omp_region *region, NULL_TREE, false, GSI_CONTINUE_LINKING); assign_stmt = gimple_build_assign (startvar, t); gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING); + if (cond_var) + { + tree itype = TREE_TYPE (cond_var); + /* For lastprivate(conditional:) itervar, we need some iteration + counter that starts at unsigned non-zero and increases. + Prefer as few IVs as possible, so if we can use startvar + itself, use that, or startvar + constant (those would be + incremented with step), and as last resort use the s0 + 1 + incremented by 1. */ + if (POINTER_TYPE_P (type) + || TREE_CODE (n1) != INTEGER_CST + || fd->loop.cond_code != LT_EXPR) + t = fold_build2 (PLUS_EXPR, itype, fold_convert (itype, s0), + build_int_cst (itype, 1)); + else if (tree_int_cst_sgn (n1) == 1) + t = fold_convert (itype, t); + else + { + tree c = fold_convert (itype, n1); + c = fold_build2 (MINUS_EXPR, itype, build_int_cst (itype, 1), c); + t = fold_build2 (PLUS_EXPR, itype, fold_convert (itype, t), c); + } + t = force_gimple_operand_gsi (&gsi, t, false, + NULL_TREE, false, GSI_CONTINUE_LINKING); + assign_stmt = gimple_build_assign (cond_var, t); + gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING); + } t = fold_convert (itype, e0); t = fold_build2 (MULT_EXPR, itype, t, step); @@ -3829,6 +3964,23 @@ expand_omp_for_static_nochunk (struct omp_region *region, assign_stmt = gimple_build_assign (vback, t); gsi_insert_before (&gsi, assign_stmt, GSI_SAME_STMT); + if (cond_var) + { + tree itype = TREE_TYPE (cond_var); + tree t2; + if (POINTER_TYPE_P (type) + || TREE_CODE (n1) != INTEGER_CST + || fd->loop.cond_code != LT_EXPR) + t2 = build_int_cst (itype, 1); + else + t2 = fold_convert (itype, step); + t2 = fold_build2 (PLUS_EXPR, itype, cond_var, t2); + t2 = force_gimple_operand_gsi (&gsi, t2, false, + NULL_TREE, true, GSI_SAME_STMT); + assign_stmt = gimple_build_assign (cond_var, t2); + gsi_insert_before (&gsi, assign_stmt, GSI_SAME_STMT); + } + t = build2 (fd->loop.cond_code, boolean_type_node, DECL_P (vback) && TREE_ADDRESSABLE (vback) ? t : vback, e); @@ -3847,7 +3999,7 @@ expand_omp_for_static_nochunk (struct omp_region *region, if (!gimple_omp_return_nowait_p (gsi_stmt (gsi))) { t = gimple_omp_return_lhs (gsi_stmt (gsi)); - if (fd->have_reductemp) + if (fd->have_reductemp || fd->lastprivate_conditional) { tree fn; if (t) @@ -3858,9 +4010,10 @@ expand_omp_for_static_nochunk (struct omp_region *region, if (t) { gimple_call_set_lhs (g, t); - gsi_insert_after (&gsi, gimple_build_assign (reductions, - NOP_EXPR, t), - GSI_SAME_STMT); + if (fd->have_reductemp) + gsi_insert_after (&gsi, gimple_build_assign (reductions, + NOP_EXPR, t), + GSI_SAME_STMT); } gsi_insert_after (&gsi, g, GSI_SAME_STMT); } @@ -3997,12 +4150,13 @@ expand_omp_for_static_chunk (struct omp_region *region, tree type, itype, vmain, vback, vextra; basic_block entry_bb, exit_bb, body_bb, seq_start_bb, iter_part_bb; basic_block trip_update_bb = NULL, cont_bb, collapse_bb = NULL, fin_bb; - gimple_stmt_iterator gsi; + gimple_stmt_iterator gsi, gsip; edge se; bool broken_loop = region->cont == NULL; tree *counts = NULL; tree n1, n2, step; tree reductions = NULL_TREE; + tree cond_var = NULL_TREE; itype = type = TREE_TYPE (fd->loop.v); if (POINTER_TYPE_P (type)) @@ -4031,6 +4185,8 @@ expand_omp_for_static_chunk (struct omp_region *region, /* Trip and adjustment setup goes in ENTRY_BB. */ gsi = gsi_last_nondebug_bb (entry_bb); gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR); + gsip = gsi; + gsi_prev (&gsip); if (fd->collapse > 1) { @@ -4090,28 +4246,64 @@ expand_omp_for_static_chunk (struct omp_region *region, gsi = gsi_last_bb (entry_bb); } - if (fd->have_reductemp) + if (fd->have_reductemp || fd->lastprivate_conditional) { tree t1 = build_int_cst (long_integer_type_node, 0); tree t2 = build_int_cst (long_integer_type_node, 1); tree t3 = build_int_cstu (long_integer_type_node, (HOST_WIDE_INT_1U << 31) + 1); tree clauses = gimple_omp_for_clauses (fd->for_stmt); - clauses = omp_find_clause (clauses, OMP_CLAUSE__REDUCTEMP_); - reductions = OMP_CLAUSE_DECL (clauses); - gcc_assert (TREE_CODE (reductions) == SSA_NAME); - gimple *g = SSA_NAME_DEF_STMT (reductions); - reductions = gimple_assign_rhs1 (g); - OMP_CLAUSE_DECL (clauses) = reductions; - gimple_stmt_iterator gsi2 = gsi_for_stmt (g); + gimple_stmt_iterator gsi2 = gsi_none (); + gimple *g = NULL; + tree mem = null_pointer_node, memv = NULL_TREE; + tree condtemp = NULL_TREE; + if (fd->have_reductemp) + { + tree c = omp_find_clause (clauses, OMP_CLAUSE__REDUCTEMP_); + reductions = OMP_CLAUSE_DECL (c); + gcc_assert (TREE_CODE (reductions) == SSA_NAME); + g = SSA_NAME_DEF_STMT (reductions); + reductions = gimple_assign_rhs1 (g); + OMP_CLAUSE_DECL (c) = reductions; + gsi2 = gsi_for_stmt (g); + } + else + { + if (gsi_end_p (gsip)) + gsi2 = gsi_after_labels (region->entry); + else + gsi2 = gsip; + reductions = null_pointer_node; + } + if (fd->lastprivate_conditional) + { + tree c = omp_find_clause (clauses, OMP_CLAUSE__CONDTEMP_); + condtemp = OMP_CLAUSE_DECL (c); + c = omp_find_clause (OMP_CLAUSE_CHAIN (c), OMP_CLAUSE__CONDTEMP_); + cond_var = OMP_CLAUSE_DECL (c); + tree type = TREE_TYPE (condtemp); + memv = create_tmp_var (type); + TREE_ADDRESSABLE (memv) = 1; + unsigned HOST_WIDE_INT sz + = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (type))); + sz *= fd->lastprivate_conditional; + expand_omp_build_assign (&gsi2, memv, build_int_cst (type, sz), + false); + mem = build_fold_addr_expr (memv); + } tree t = build_call_expr (builtin_decl_explicit (BUILT_IN_GOMP_LOOP_START), 9, t1, t2, t2, t3, t1, null_pointer_node, - null_pointer_node, reductions, null_pointer_node); + null_pointer_node, reductions, mem); force_gimple_operand_gsi (&gsi2, t, true, NULL_TREE, true, GSI_SAME_STMT); - gsi_remove (&gsi2, true); - release_ssa_name (gimple_assign_lhs (g)); + if (fd->lastprivate_conditional) + expand_omp_build_assign (&gsi2, condtemp, memv, false); + if (fd->have_reductemp) + { + gsi_remove (&gsi2, true); + release_ssa_name (gimple_assign_lhs (g)); + } } switch (gimple_omp_for_kind (fd->for_stmt)) { @@ -4286,6 +4478,33 @@ expand_omp_for_static_chunk (struct omp_region *region, NULL_TREE, false, GSI_CONTINUE_LINKING); assign_stmt = gimple_build_assign (startvar, t); gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING); + if (cond_var) + { + tree itype = TREE_TYPE (cond_var); + /* For lastprivate(conditional:) itervar, we need some iteration + counter that starts at unsigned non-zero and increases. + Prefer as few IVs as possible, so if we can use startvar + itself, use that, or startvar + constant (those would be + incremented with step), and as last resort use the s0 + 1 + incremented by 1. */ + if (POINTER_TYPE_P (type) + || TREE_CODE (n1) != INTEGER_CST + || fd->loop.cond_code != LT_EXPR) + t = fold_build2 (PLUS_EXPR, itype, fold_convert (itype, s0), + build_int_cst (itype, 1)); + else if (tree_int_cst_sgn (n1) == 1) + t = fold_convert (itype, t); + else + { + tree c = fold_convert (itype, n1); + c = fold_build2 (MINUS_EXPR, itype, build_int_cst (itype, 1), c); + t = fold_build2 (PLUS_EXPR, itype, fold_convert (itype, t), c); + } + t = force_gimple_operand_gsi (&gsi, t, false, + NULL_TREE, false, GSI_CONTINUE_LINKING); + assign_stmt = gimple_build_assign (cond_var, t); + gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING); + } t = fold_convert (itype, e0); t = fold_build2 (MULT_EXPR, itype, t, step); @@ -4416,7 +4635,7 @@ expand_omp_for_static_chunk (struct omp_region *region, if (!gimple_omp_return_nowait_p (gsi_stmt (gsi))) { t = gimple_omp_return_lhs (gsi_stmt (gsi)); - if (fd->have_reductemp) + if (fd->have_reductemp || fd->lastprivate_conditional) { tree fn; if (t) @@ -4427,9 +4646,10 @@ expand_omp_for_static_chunk (struct omp_region *region, if (t) { gimple_call_set_lhs (g, t); - gsi_insert_after (&gsi, gimple_build_assign (reductions, - NOP_EXPR, t), - GSI_SAME_STMT); + if (fd->have_reductemp) + gsi_insert_after (&gsi, gimple_build_assign (reductions, + NOP_EXPR, t), + GSI_SAME_STMT); } gsi_insert_after (&gsi, g, GSI_SAME_STMT); } @@ -6043,7 +6263,7 @@ expand_omp_for (struct omp_region *region, gimple *inner_stmt) else start_ix = ((int)BUILT_IN_GOMP_LOOP_STATIC_START) + fn_index; next_ix = ((int)BUILT_IN_GOMP_LOOP_STATIC_NEXT) + fn_index; - if (fd.have_reductemp) + if (fd.have_reductemp || fd.lastprivate_conditional) { if (fd.ordered) start_ix = (int)BUILT_IN_GOMP_LOOP_DOACROSS_START; diff --git a/gcc/omp-general.c b/gcc/omp-general.c index 4a9b15ccde4..baab7619135 100644 --- a/gcc/omp-general.c +++ b/gcc/omp-general.c @@ -168,6 +168,7 @@ omp_extract_for_data (gomp_for *for_stmt, struct omp_for_data *fd, fd->have_nowait = distribute || simd; fd->have_ordered = false; fd->have_reductemp = false; + fd->lastprivate_conditional = 0; fd->tiling = NULL_TREE; fd->collapse = 1; fd->ordered = 0; @@ -220,6 +221,11 @@ omp_extract_for_data (gomp_for *for_stmt, struct omp_for_data *fd, break; case OMP_CLAUSE__REDUCTEMP_: fd->have_reductemp = true; + break; + case OMP_CLAUSE_LASTPRIVATE: + if (OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (t)) + fd->lastprivate_conditional++; + break; default: break; } diff --git a/gcc/omp-general.h b/gcc/omp-general.h index f96d3c7768a..b89c13170a2 100644 --- a/gcc/omp-general.h +++ b/gcc/omp-general.h @@ -63,6 +63,7 @@ struct omp_for_data int collapse; /* Collapsed loops, 1 for a non-collapsed loop. */ int ordered; bool have_nowait, have_ordered, simd_schedule, have_reductemp; + int lastprivate_conditional; unsigned char sched_modifiers; enum omp_clause_schedule_kind sched_kind; struct omp_for_data_loop *loops; diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 26ee70db0b3..faab5d38428 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -119,10 +119,14 @@ struct omp_context and then offsets (if constant, otherwise NULL) for each entry. */ vec task_reductions; - /* And a hash map from the reduction clauses to the registered array + /* A hash map from the reduction clauses to the registered array elts. */ hash_map *task_reduction_map; + /* And a hash map from the lastprivate(conditional:) variables to their + corresponding tracking loop iteration variables. */ + hash_map *lastprivate_conditional_map; + /* Nesting depth of this context. Used to beautify error messages re invalid gotos. The outermost ctx is depth 1, with depth 0 being reserved for the main body of the function. */ @@ -955,6 +959,8 @@ delete_omp_context (splay_tree_value value) delete ctx->task_reduction_map; } + delete ctx->lastprivate_conditional_map; + XDELETE (ctx); } @@ -5358,18 +5364,72 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, } } +/* Create temporary variables for lastprivate(conditional:) implementation + in context CTX with CLAUSES. */ + +static void +lower_lastprivate_conditional_clauses (tree *clauses, omp_context *ctx) +{ + struct omp_for_data fd; + tree iter_type = NULL_TREE; + tree cond_ptr = NULL_TREE; + tree iter_var = NULL_TREE; + for (tree c = *clauses; c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE + && OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c)) + { + if (iter_type == NULL) + { + omp_extract_for_data (as_a (ctx->stmt), &fd, NULL); + iter_type = unsigned_type_for (fd.iter_type); + cond_ptr = create_tmp_var_raw (build_pointer_type (iter_type)); + DECL_CONTEXT (cond_ptr) = current_function_decl; + DECL_SEEN_IN_BIND_EXPR_P (cond_ptr) = 1; + DECL_CHAIN (cond_ptr) = ctx->block_vars; + ctx->block_vars = cond_ptr; + iter_var = create_tmp_var_raw (iter_type); + DECL_CONTEXT (iter_var) = current_function_decl; + DECL_SEEN_IN_BIND_EXPR_P (iter_var) = 1; + DECL_CHAIN (iter_var) = ctx->block_vars; + ctx->block_vars = iter_var; + tree c2 + = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE__CONDTEMP_); + tree c3 + = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE__CONDTEMP_); + OMP_CLAUSE_DECL (c2) = cond_ptr; + OMP_CLAUSE_DECL (c3) = iter_var; + OMP_CLAUSE_CHAIN (c2) = c3; + OMP_CLAUSE_CHAIN (c3) = *clauses; + *clauses = c2; + ctx->lastprivate_conditional_map = new hash_map; + } + tree v = create_tmp_var_raw (iter_type); + DECL_CONTEXT (v) = current_function_decl; + DECL_SEEN_IN_BIND_EXPR_P (v) = 1; + DECL_CHAIN (v) = ctx->block_vars; + ctx->block_vars = v; + tree o = lookup_decl (OMP_CLAUSE_DECL (c), ctx); + ctx->lastprivate_conditional_map->put (o, v); + } +} + /* Generate code to implement the LASTPRIVATE clauses. This is used for both parallel and workshare constructs. PREDICATE may be NULL if it's - always true. */ + always true. BODY_P is the sequence to insert early initialization + if needed, STMT_LIST is where the non-conditional lastprivate handling + goes into and CSTMT_LIST is a sequence that needs to be run in a critical + section. */ static void -lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list, +lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *body_p, + gimple_seq *stmt_list, gimple_seq *cstmt_list, omp_context *ctx) { tree x, c, label = NULL, orig_clauses = clauses; bool par_clauses = false; tree simduid = NULL, lastlane = NULL, simtcond = NULL, simtlast = NULL; + unsigned HOST_WIDE_INT conditional_off = 0; /* Early exit if there are no lastprivate or linear clauses. */ for (; clauses ; clauses = OMP_CLAUSE_CHAIN (clauses)) @@ -5448,10 +5508,43 @@ lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list, gimple_seq_add_stmt (stmt_list, gimple_build_label (label_true)); } + tree cond_ptr = NULL_TREE; for (c = clauses; c ;) { tree var, new_var; location_t clause_loc = OMP_CLAUSE_LOCATION (c); + gimple_seq *this_stmt_list = stmt_list; + tree lab2 = NULL_TREE; + + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE + && OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c)) + { + gcc_assert (body_p && ctx->lastprivate_conditional_map); + if (cond_ptr == NULL_TREE) + { + cond_ptr = omp_find_clause (orig_clauses, OMP_CLAUSE__CONDTEMP_); + cond_ptr = OMP_CLAUSE_DECL (cond_ptr); + } + tree type = TREE_TYPE (TREE_TYPE (cond_ptr)); + tree o = lookup_decl (OMP_CLAUSE_DECL (c), ctx); + tree v = *ctx->lastprivate_conditional_map->get (o); + gimplify_assign (v, build_zero_cst (type), body_p); + this_stmt_list = cstmt_list; + tree mem = build2 (MEM_REF, type, cond_ptr, + build_int_cst (TREE_TYPE (cond_ptr), + conditional_off)); + tree mem2 = copy_node (mem); + conditional_off += tree_to_uhwi (TYPE_SIZE_UNIT (type)); + gimple_seq seq = NULL; + mem = force_gimple_operand (mem, &seq, true, NULL_TREE); + gimple_seq_add_seq (this_stmt_list, seq); + tree lab1 = create_artificial_label (UNKNOWN_LOCATION); + lab2 = create_artificial_label (UNKNOWN_LOCATION); + gimple *g = gimple_build_cond (GT_EXPR, v, mem, lab1, lab2); + gimple_seq_add_stmt (this_stmt_list, g); + gimple_seq_add_stmt (this_stmt_list, gimple_build_label (lab1)); + gimplify_assign (mem2, v, this_stmt_list); + } if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE || (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR @@ -5493,7 +5586,7 @@ lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list, 2, simduid, TREE_OPERAND (val, 1)); gimple_call_set_lhs (g, lastlane); - gimple_seq_add_stmt (stmt_list, g); + gimple_seq_add_stmt (this_stmt_list, g); } new_var = build4 (ARRAY_REF, TREE_TYPE (val), TREE_OPERAND (val, 0), lastlane, @@ -5511,13 +5604,13 @@ lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list, gcall *g = gimple_build_call_internal (IFN_GOMP_SIMT_LAST_LANE, 1, simtcond); gimple_call_set_lhs (g, simtlast); - gimple_seq_add_stmt (stmt_list, g); + gimple_seq_add_stmt (this_stmt_list, g); } x = build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_GOMP_SIMT_XCHG_IDX, TREE_TYPE (val), 2, val, simtlast); new_var = unshare_expr (new_var); - gimplify_assign (new_var, x, stmt_list); + gimplify_assign (new_var, x, this_stmt_list); new_var = unshare_expr (new_var); } @@ -5525,7 +5618,7 @@ lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list, && OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c)) { lower_omp (&OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c), ctx); - gimple_seq_add_seq (stmt_list, + gimple_seq_add_seq (this_stmt_list, OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c)); OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c) = NULL; } @@ -5533,7 +5626,7 @@ lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list, && OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c)) { lower_omp (&OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c), ctx); - gimple_seq_add_seq (stmt_list, + gimple_seq_add_seq (this_stmt_list, OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c)); OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c) = NULL; } @@ -5553,8 +5646,12 @@ lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list, if (omp_is_reference (var)) new_var = build_simple_mem_ref_loc (clause_loc, new_var); x = lang_hooks.decls.omp_clause_assign_op (c, x, new_var); - gimplify_and_add (x, stmt_list); + gimplify_and_add (x, this_stmt_list); + + if (lab2) + gimple_seq_add_stmt (this_stmt_list, gimple_build_label (lab2)); } + c = OMP_CLAUSE_CHAIN (c); if (c == NULL && !par_clauses) { @@ -5802,10 +5899,15 @@ lower_oacc_reductions (location_t loc, tree clauses, tree level, bool inner, gimple_seq_add_seq (join_seq, after_join); } -/* Generate code to implement the REDUCTION clauses. */ +/* Generate code to implement the REDUCTION clauses, append it + to STMT_SEQP. CLIST if non-NULL is a pointer to a sequence + that should be emitted also inside of the critical section, + in that case clear *CLIST afterwards, otherwise leave it as is + and let the caller emit it itself. */ static void -lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp, omp_context *ctx) +lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp, + gimple_seq *clist, omp_context *ctx) { gimple_seq sub_seq = NULL; gimple *stmt; @@ -6047,6 +6149,12 @@ lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp, omp_context *ctx) gimple_seq_add_seq (stmt_seqp, sub_seq); + if (clist) + { + gimple_seq_add_seq (stmt_seqp, *clist); + *clist = NULL; + } + stmt = gimple_build_call (builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_END), 0); gimple_seq_add_stmt (stmt_seqp, stmt); @@ -6684,7 +6792,7 @@ lower_omp_sections (gimple_stmt_iterator *gsi_p, omp_context *ctx) { gimple_seq l = NULL; lower_lastprivate_clauses (gimple_omp_sections_clauses (stmt), NULL, - &l, ctx); + NULL, &l, NULL, ctx); gsi_insert_seq_after (&tgsi, l, GSI_CONTINUE_LINKING); gimple_omp_section_set_last (sec_start); } @@ -6697,7 +6805,8 @@ lower_omp_sections (gimple_stmt_iterator *gsi_p, omp_context *ctx) bind = gimple_build_bind (NULL, new_body, block); olist = NULL; - lower_reduction_clauses (gimple_omp_sections_clauses (stmt), &olist, ctx); + lower_reduction_clauses (gimple_omp_sections_clauses (stmt), &olist, + NULL, ctx); block = make_node (BLOCK); new_stmt = gimple_build_bind (NULL, NULL, block); @@ -8074,11 +8183,13 @@ lower_omp_critical (gimple_stmt_iterator *gsi_p, omp_context *ctx) for a lastprivate clause. Given a loop control predicate of (V cond N2), we gate the clause on (!(V cond N2)). The lowered form is appended to *DLIST, iterator initialization is appended to - *BODY_P. */ + *BODY_P. *CLIST is for lastprivate(conditional:) code that needs + to be emitted in a critical section. */ static void lower_omp_for_lastprivate (struct omp_for_data *fd, gimple_seq *body_p, - gimple_seq *dlist, struct omp_context *ctx) + gimple_seq *dlist, gimple_seq *clist, + struct omp_context *ctx) { tree clauses, cond, vinit; enum tree_code cond_code; @@ -8158,7 +8269,7 @@ lower_omp_for_lastprivate (struct omp_for_data *fd, gimple_seq *body_p, clauses = gimple_omp_for_clauses (fd->for_stmt); stmts = NULL; - lower_lastprivate_clauses (clauses, cond, &stmts, ctx); + lower_lastprivate_clauses (clauses, cond, body_p, &stmts, clist, ctx); if (!gimple_seq_empty_p (stmts)) { gimple_seq_add_seq (&stmts, *dlist); @@ -8190,7 +8301,7 @@ lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx) gomp_for *stmt = as_a (gsi_stmt (*gsi_p)); gbind *new_stmt; gimple_seq omp_for_body, body, dlist, tred_ilist = NULL, tred_dlist = NULL; - gimple_seq cnt_list = NULL; + gimple_seq cnt_list = NULL, clist = NULL; gimple_seq oacc_head = NULL, oacc_tail = NULL; size_t i; @@ -8308,6 +8419,9 @@ lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx) gimple_seq_add_seq (rclauses ? &tred_ilist : &body, gimple_omp_for_pre_body (stmt)); + lower_lastprivate_conditional_clauses (gimple_omp_for_clauses_ptr (stmt), + ctx); + lower_omp (gimple_omp_body_ptr (stmt), ctx); /* Lower the header expressions. At this point, we can assume that @@ -8353,7 +8467,7 @@ lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx) if (oacc_head) gimple_seq_add_seq (&body, oacc_head); - lower_omp_for_lastprivate (&fd, &body, &dlist, ctx); + lower_omp_for_lastprivate (&fd, &body, &dlist, &clist, ctx); if (gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_FOR) for (tree c = gimple_omp_for_clauses (stmt); c; c = OMP_CLAUSE_CHAIN (c)) @@ -8378,7 +8492,18 @@ lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx) fd.loop.v)); /* After the loop, add exit clauses. */ - lower_reduction_clauses (gimple_omp_for_clauses (stmt), &body, ctx); + lower_reduction_clauses (gimple_omp_for_clauses (stmt), &body, &clist, ctx); + + if (clist) + { + tree fndecl = builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_START); + gcall *g = gimple_build_call (fndecl, 0); + gimple_seq_add_stmt (&body, g); + gimple_seq_add_seq (&body, clist); + fndecl = builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_END); + g = gimple_build_call (fndecl, 0); + gimple_seq_add_stmt (&body, g); + } if (ctx->cancellable) gimple_seq_add_stmt (&body, gimple_build_label (ctx->cancel_label)); @@ -9000,7 +9125,7 @@ lower_omp_taskreg (gimple_stmt_iterator *gsi_p, omp_context *ctx) lower_rec_input_clauses (clauses, &par_ilist, &par_olist, ctx, NULL); lower_omp (&par_body, ctx); if (gimple_code (stmt) == GIMPLE_OMP_PARALLEL) - lower_reduction_clauses (clauses, &par_rlist, ctx); + lower_reduction_clauses (clauses, &par_rlist, NULL, ctx); /* Declare all the variables created by mapping and the variables declared in the scope of the parallel body. */ @@ -10189,7 +10314,8 @@ lower_omp_teams (gimple_stmt_iterator *gsi_p, omp_context *ctx) lower_rec_input_clauses (gimple_omp_teams_clauses (teams_stmt), &bind_body, &dlist, ctx, NULL); lower_omp (gimple_omp_body_ptr (teams_stmt), ctx); - lower_reduction_clauses (gimple_omp_teams_clauses (teams_stmt), &olist, ctx); + lower_reduction_clauses (gimple_omp_teams_clauses (teams_stmt), &olist, + NULL, ctx); if (!gimple_omp_teams_grid_phony (teams_stmt)) { gimple_seq_add_stmt (&bind_body, teams_stmt); @@ -10498,8 +10624,28 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context *ctx) default: break; } + goto regimplify; + + case GIMPLE_ASSIGN: + if (ctx && ctx->lastprivate_conditional_map) + { + tree lhs = get_base_address (gimple_assign_lhs (stmt)); + if (DECL_P (lhs)) + if (tree *v = ctx->lastprivate_conditional_map->get (lhs)) + { + tree clauses + = gimple_omp_for_clauses (as_a (ctx->stmt)); + tree c = omp_find_clause (clauses, OMP_CLAUSE__CONDTEMP_); + c = omp_find_clause (OMP_CLAUSE_CHAIN (c), + OMP_CLAUSE__CONDTEMP_); + gimple *g = gimple_build_assign (*v, OMP_CLAUSE_DECL (c)); + gsi_insert_after (gsi_p, g, GSI_SAME_STMT); + } + } /* FALLTHRU */ + default: + regimplify: if ((ctx || task_shared_vars) && walk_gimple_op (stmt, lower_omp_regimplify_p, ctx ? NULL : &wi)) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 95b0c9db567..a0cff00b621 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2019-05-24 Jakub Jelinek + + * c-c++-common/gomp/lastprivate-conditional-2.c (foo): Don't expect + sorry for omp for. + * c-c++-common/gomp/lastprivate-conditional-3.c: New test. + 2019-05-24 Richard Biener PR testsuite/90607 diff --git a/gcc/testsuite/c-c++-common/gomp/lastprivate-conditional-2.c b/gcc/testsuite/c-c++-common/gomp/lastprivate-conditional-2.c index 4b1d2ca9163..34c7e12287b 100644 --- a/gcc/testsuite/c-c++-common/gomp/lastprivate-conditional-2.c +++ b/gcc/testsuite/c-c++-common/gomp/lastprivate-conditional-2.c @@ -4,7 +4,7 @@ foo (int *p) int a = -1, b = -1, c = -1, d = -1, e = -1, f = -1, g = -1, h = -1; int i; #pragma omp parallel - #pragma omp for lastprivate (conditional: a) /* { dg-message "not supported yet" } */ + #pragma omp for lastprivate (conditional: a) for (i = 0; i < 32; i++) if (p[i]) a = i; diff --git a/gcc/testsuite/c-c++-common/gomp/lastprivate-conditional-3.c b/gcc/testsuite/c-c++-common/gomp/lastprivate-conditional-3.c new file mode 100644 index 00000000000..bf413ec8d9b --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/lastprivate-conditional-3.c @@ -0,0 +1,26 @@ +void +foo (int *p) +{ + int i, j, k; + #pragma omp parallel + { + #pragma omp for lastprivate (conditional: i) /* { dg-warning "conditional 'lastprivate' on loop iterator 'i' ignored" } */ + for (i = 0; i < 32; i++) + ; + #pragma omp for collapse (3) lastprivate (conditional: i) /* { dg-warning "conditional 'lastprivate' on loop iterator 'i' ignored" } */ + for (i = 0; i < 32; i++) + for (j = 0; j < 32; ++j) + for (k = 0; k < 2; ++k) + ; + #pragma omp for collapse (3) lastprivate (conditional: j) /* { dg-warning "conditional 'lastprivate' on loop iterator 'j' ignored" } */ + for (i = 0; i < 32; i++) + for (j = 0; j < 32; ++j) + for (k = 0; k < 2; ++k) + ; + #pragma omp for collapse (3) lastprivate (conditional: k) /* { dg-warning "conditional 'lastprivate' on loop iterator 'k' ignored" } */ + for (i = 0; i < 32; i++) + for (j = 0; j < 32; ++j) + for (k = 0; k < 2; ++k) + ; + } +} diff --git a/gcc/tree-core.h b/gcc/tree-core.h index fbed0c379b2..26cfa7ea19f 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -343,6 +343,9 @@ enum omp_clause_code { /* Internal clause: temporary for task reductions. */ OMP_CLAUSE__REDUCTEMP_, + /* Internal clause: temporary for lastprivate(conditional:). */ + OMP_CLAUSE__CONDTEMP_, + /* OpenACC/OpenMP clause: if (scalar-expression). */ OMP_CLAUSE_IF, diff --git a/gcc/tree-nested.c b/gcc/tree-nested.c index 3fe23cc2b22..cdffb2e1495 100644 --- a/gcc/tree-nested.c +++ b/gcc/tree-nested.c @@ -1369,6 +1369,7 @@ convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) function decomposition happens before that. */ case OMP_CLAUSE__LOOPTEMP_: case OMP_CLAUSE__REDUCTEMP_: + case OMP_CLAUSE__CONDTEMP_: case OMP_CLAUSE__SIMDUID_: case OMP_CLAUSE__GRIDDIM_: case OMP_CLAUSE__SIMT_: @@ -2096,6 +2097,7 @@ convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) function decomposition happens before that. */ case OMP_CLAUSE__LOOPTEMP_: case OMP_CLAUSE__REDUCTEMP_: + case OMP_CLAUSE__CONDTEMP_: case OMP_CLAUSE__SIMDUID_: case OMP_CLAUSE__GRIDDIM_: case OMP_CLAUSE__SIMT_: diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 6645a646617..4ba9170ddd3 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -466,6 +466,9 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags) case OMP_CLAUSE__REDUCTEMP_: name = "_reductemp_"; goto print_remap; + case OMP_CLAUSE__CONDTEMP_: + name = "_condtemp_"; + goto print_remap; case OMP_CLAUSE_TO_DECLARE: name = "to"; goto print_remap; diff --git a/gcc/tree.c b/gcc/tree.c index cc8b4b8e709..9a8f5e56742 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -308,6 +308,7 @@ unsigned const char omp_clause_num_ops[] = 0, /* OMP_CLAUSE_SEQ */ 1, /* OMP_CLAUSE__LOOPTEMP_ */ 1, /* OMP_CLAUSE__REDUCTEMP_ */ + 1, /* OMP_CLAUSE__CONDTEMP_ */ 1, /* OMP_CLAUSE_IF */ 1, /* OMP_CLAUSE_NUM_THREADS */ 1, /* OMP_CLAUSE_SCHEDULE */ @@ -385,6 +386,7 @@ const char * const omp_clause_code_name[] = "seq", "_looptemp_", "_reductemp_", + "_condtemp_", "if", "num_threads", "schedule", @@ -12304,6 +12306,7 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, case OMP_CLAUSE_IS_DEVICE_PTR: case OMP_CLAUSE__LOOPTEMP_: case OMP_CLAUSE__REDUCTEMP_: + case OMP_CLAUSE__CONDTEMP_: case OMP_CLAUSE__SIMDUID_: WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, 0)); /* FALLTHRU */ diff --git a/gcc/tree.h b/gcc/tree.h index 3a1e6767cee..72544b63d79 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1439,7 +1439,7 @@ class auto_suppress_location_wrappers #define OMP_CLAUSE_DECL(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE), \ OMP_CLAUSE_PRIVATE, \ - OMP_CLAUSE__REDUCTEMP_), 0) + OMP_CLAUSE__CONDTEMP_), 0) #define OMP_CLAUSE_HAS_LOCATION(NODE) \ (LOCATION_LOCUS ((OMP_CLAUSE_CHECK (NODE))->omp_clause.locus) \ != UNKNOWN_LOCATION) diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog index 5b427abc192..f88e06abf68 100644 --- a/libgomp/ChangeLog +++ b/libgomp/ChangeLog @@ -1,5 +1,8 @@ 2019-05-24 Jakub Jelinek + * testsuite/libgomp.c-c++-common/lastprivate-conditional-1.c: New test. + * testsuite/libgomp.c-c++-common/lastprivate-conditional-2.c: New test. + PR libgomp/90585 * plugin/plugin-hsa.c: Include gstdint.h. Include inttypes.h only if HAVE_INTTYPES_H is defined. diff --git a/libgomp/testsuite/libgomp.c-c++-common/lastprivate-conditional-1.c b/libgomp/testsuite/libgomp.c-c++-common/lastprivate-conditional-1.c new file mode 100644 index 00000000000..a7e9f90c5a8 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/lastprivate-conditional-1.c @@ -0,0 +1,144 @@ +/* { dg-do run } */ +/* { dg-require-effective-target tls_runtime } */ +/* { dg-additional-options "-std=gnu99" {target c } } */ + +#include +#include + +int r, s, u, v, r2, s2, u2, v2, r3, s3, u3, v3; +long long w, w2, w3, p, p2, p3; +int *x, *x2, *x3; +short y, y2, y3; +int z; +int thr1, thr2; +#pragma omp threadprivate (thr1, thr2) + +void +foo (int *a, long long int b, long long int c) +{ + int i; + long long j; + #pragma omp for lastprivate (conditional: u, x) nowait + for (i = 15; i < 64; i++) + { + if ((a[i] % 5) == 3) + u = i; + if ((a[i] % 7) == 2) + x = &a[i]; + } + #pragma omp for nowait lastprivate (conditional: v) reduction (+:r, s) schedule (nonmonotonic: static) + for (i = -3; i < 119; i += 2) + { + ++s; + if ((a[i + 4] % 11) == 9) + v = i; + else + ++r; + } + #pragma omp for schedule (monotonic: static) lastprivate (conditional: w) nowait + for (j = b; j < b + 115 * c; j += (b & 3) + 7) + if ((a[j] % 13) == 5) + w = j * 2; + #pragma omp for schedule (auto) lastprivate (conditional: p) collapse(3) + for (i = -5; i < (int) (b + 5); i += 2) + for (j = b + 12 + c; j > b; --j) + for (int k = 0; k < 5; k += c) + if (((((i + 5) * 13 + (13 - j)) * 5 + k) % 17) == 6) + p = i * 10000 + j * 100 + k; + + #pragma omp for schedule (nonmonotonic: static, 2) nowait lastprivate (conditional: u2, x2) + for (i = 15; i < 64; i++) + { + if ((a[i] % 5) == 3) + u2 = i; + if ((a[i] % 7) == 2) + x2 = &a[i]; + } + #pragma omp for schedule (static, 3) lastprivate (conditional: v2) reduction (+:r2, s2) + for (i = -3; i < 119; i += 2) + { + ++s2; + if ((a[i + 4] % 11) == 9) + v2 = i; + else + ++r2; + } + #pragma omp for lastprivate (conditional: w2) schedule (static, 1) nowait + for (j = b; j < b + 115 * c; j += (b & 3) + 7) + if ((a[j] % 13) == 5) + w2 = j * 2; + #pragma omp for schedule (static, 3) collapse (3) lastprivate (conditional: p2) + for (i = -5; i < (int) (b + 5); i += 2) + for (j = b + 12 + c; j > b; --j) + for (int k = 0; k < 5; k += c) + if (((((i + 5) * 13 + (13 - j)) * 5 + k) % 17) == 6) + p2 = i * 10000 + j * 100 + k; + + #pragma omp for lastprivate (conditional: u3, x3) nowait schedule (runtime) + for (i = 15; i < 64; i++) + { + if ((a[i] % 5) == 3) + u3 = i; + if ((a[i] % 7) == 2) + x3 = &a[i]; + } + #pragma omp for nowait lastprivate (conditional: v3) reduction (+:r3, s3) schedule (nonmonotonic: dynamic) + for (i = -3; i < 119; i += 2) + { + ++s3; + if ((a[i + 4] % 11) == 9) + v3 = i; + else + ++r3; + } + #pragma omp for schedule (monotonic: guided, 3) lastprivate (conditional: w3) nowait + for (j = b; j < b + 115 * c; j += (b & 3) + 7) + if ((a[j] % 13) == 5) + w3 = j * 2; + #pragma omp for schedule (dynamic, 4) lastprivate (conditional: p3) collapse(3) + for (i = -5; i < (int) (b + 5); i += 2) + for (j = b + 12 + c; j > b; --j) + for (int k = 0; k < 5; k += c) + if (((((i + 5) * 13 + (13 - j)) * 5 + k) % 17) == 6) + p3 = i * 10000 + j * 100 + k; + + /* Nasty testcase, verify that even a no-op assignment is accounted + for in lastprivate(conditional:). */ + #pragma omp for schedule (monotonic: static, 2) firstprivate (z) \ + lastprivate (conditional: z) + for (int k = -2000; k < 8000; ++k) + { + if (k < 3000 && (k & 3) == 1) + { + z = k; + thr1 = k; + } + else if (k == 7931) + { + z = z; + thr2 = 1; + } + } + + if (thr2 && z != thr1) + abort (); +} + +int +main () +{ + int a[128], i; + volatile int j = 0; + for (i = 0; i < 128; i++) + a[i] = i; + w = 1234; + #pragma omp parallel + foo (a, j, j + 1); + if (u != 63 || v != 115 || w != 140 || x != &a[58] || r != 55 || s != 61 || p != 30104) + abort (); + if (u2 != 63 || v2 != 115 || w2 != 140 || x2 != &a[58] || r2 != 55 || s2 != 61 || p2 != 30104) + abort (); + if (u3 != 63 || v3 != 115 || w3 != 140 || x3 != &a[58] || r3 != 55 || s3 != 61 || p3 != 30104) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/lastprivate-conditional-2.c b/libgomp/testsuite/libgomp.c-c++-common/lastprivate-conditional-2.c new file mode 100644 index 00000000000..f252206f5b3 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/lastprivate-conditional-2.c @@ -0,0 +1,171 @@ +/* { dg-do run } */ +/* { dg-require-effective-target tls_runtime } */ +/* { dg-additional-options "-std=gnu99" {target c } } */ + +#include +#include + +int r, s, u, v, r2, s2, u2, v2, r3, s3, u3, v3, t; +long long w, w2, w3, p, p2, p3; +int *x, *x2, *x3; +short y, y2, y3; +int z; +int thr1, thr2; +#pragma omp threadprivate (thr1, thr2) + +void +foo (int *a, long long int b, long long int c) +{ + int i; + long long j; + #pragma omp for lastprivate (conditional: u, x) reduction (task, +: t) + for (i = 15; i < 64; i++) + { + ++t; + if ((a[i] % 5) == 3) + u = i; + if ((a[i] % 7) == 2) + x = &a[i]; + } + #pragma omp for lastprivate (conditional: v) reduction (+:r, s) schedule (nonmonotonic: static) reduction (task, +: t) + for (i = -3; i < 119; i += 2) + { + ++s; + ++t; + if ((a[i + 4] % 11) == 9) + v = i; + else + ++r; + } + #pragma omp for schedule (monotonic: static) lastprivate (conditional: w) reduction (task, +: t) + for (j = b; j < b + 115 * c; j += (b & 3) + 7) + { + if ((a[j] % 13) == 5) + w = j * 2; + ++t; + } + #pragma omp for schedule (auto) lastprivate (conditional: p) collapse(3) reduction (task, +: t) + for (i = -5; i < (int) (b + 5); i += 2) + for (j = b + 12 + c; j > b; --j) + for (int k = 0; k < 5; k += c) + { + ++t; + if (((((i + 5) * 13 + (13 - j)) * 5 + k) % 17) == 6) + p = i * 10000 + j * 100 + k; + } + + #pragma omp for schedule (nonmonotonic: static, 2) reduction (task, +: t) lastprivate (conditional: u2, x2) + for (i = 15; i < 64; i++) + { + if ((a[i] % 5) == 3) + u2 = i; + if ((a[i] % 7) == 2) + x2 = &a[i]; + t++; + } + #pragma omp for schedule (static, 3) lastprivate (conditional: v2) reduction (+:r2, s2) reduction (task, +: t) + for (i = -3; i < 119; i += 2) + { + ++s2; + if ((a[i + 4] % 11) == 9) + v2 = i; + else + ++r2; + t++; + } + #pragma omp for lastprivate (conditional: w2) schedule (static, 1) reduction (task, +: t) + for (j = b; j < b + 115 * c; j += (b & 3) + 7) + { + if ((a[j] % 13) == 5) + w2 = j * 2; + t += 1; + } + #pragma omp for schedule (static, 3) collapse (3) reduction (task, +: t) lastprivate (conditional: p2) + for (i = -5; i < (int) (b + 5); i += 2) + for (j = b + 12 + c; j > b; --j) + for (int k = 0; k < 5; k += c) + { + ++t; + if (((((i + 5) * 13 + (13 - j)) * 5 + k) % 17) == 6) + p2 = i * 10000 + j * 100 + k; + } + + #pragma omp for lastprivate (conditional: u3, x3) reduction (task, +: t) schedule (runtime) + for (i = 15; i < 64; i++) + { + t = t + 1; + if ((a[i] % 5) == 3) + u3 = i; + if ((a[i] % 7) == 2) + x3 = &a[i]; + } + #pragma omp for reduction (task, +: t) lastprivate (conditional: v3) reduction (+:r3, s3) schedule (nonmonotonic: dynamic) + for (i = -3; i < 119; i += 2) + { + ++s3; + if ((a[i + 4] % 11) == 9) + v3 = i; + else + ++r3; + ++t; + } + #pragma omp for schedule (monotonic: guided, 3) lastprivate (conditional: w3) reduction (task, +: t) + for (j = b; j < b + 115 * c; j += (b & 3) + 7) + { + if ((a[j] % 13) == 5) + w3 = j * 2; + t++; + } + #pragma omp for schedule (dynamic, 4) lastprivate (conditional: p3) collapse(3) reduction (task, +: t) + for (i = -5; i < (int) (b + 5); i += 2) + for (j = b + 12 + c; j > b; --j) + for (int k = 0; k < 5; k += c) + { + ++t; + if (((((i + 5) * 13 + (13 - j)) * 5 + k) % 17) == 6) + p3 = i * 10000 + j * 100 + k; + } + + /* Nasty testcase, verify that even a no-op assignment is accounted + for in lastprivate(conditional:). */ + #pragma omp for schedule (monotonic: static, 2) firstprivate (z) \ + lastprivate (conditional: z) reduction (task, +: t) + for (int k = -2000; k < 8000; ++k) + { + t++; + if (k < 3000 && (k & 3) == 1) + { + z = k; + thr1 = k; + } + else if (k == 7931) + { + z = z; + thr2 = 1; + } + } + + if (thr2 && z != thr1) + abort (); +} + +int +main () +{ + int a[128], i; + volatile int j = 0; + for (i = 0; i < 128; i++) + a[i] = i; + w = 1234; + #pragma omp parallel + foo (a, j, j + 1); + if (u != 63 || v != 115 || w != 140 || x != &a[58] || r != 55 || s != 61 || p != 30104) + abort (); + if (u2 != 63 || v2 != 115 || w2 != 140 || x2 != &a[58] || r2 != 55 || s2 != 61 || p2 != 30104) + abort (); + if (u3 != 63 || v3 != 115 || w3 != 140 || x3 != &a[58] || r3 != 55 || s3 != 61 || p3 != 30104) + abort (); + if (t != 11356) + abort (); + return 0; +} -- 2.11.4.GIT