Hi! In C/C++, OpenMP 4.1 is going to allow array sections and arrays in reduction clauses. This patch implements it. Committed to gomp-4_1-branch.
2015-06-10 Jakub Jelinek <ja...@redhat.com> * tree.c (omp_clause_num_ops): Bump number of OMP_CLAUSE_REDUCTION arguments to 5. (walk_tree_1): Adjust for 5 instead of 4 OMP_CLAUSE_REDUCTION arguments. * tree-core.h (OMP_CLAUSE_REDUCTION): Document OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER. * tree.h (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER): Define. * tree-nested.c (convert_nonlocal_omp_clauses, convert_local_omp_clauses): Temporarily adjust context of OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER too if non-NULL. * gimplify.c (omp_add_variable): Call omp_notice_variable on TYPE_SIZE_UNIT only if it is a DECL_P. (find_decl_expr): New function. (gimplify_scan_omp_clauses): Handle OMP_CLAUSE_REDUCTION with MEM_REF OMP_CLAUSE_DECL. * omp-low.c (scan_sharing_clauses, lower_rec_input_clauses, lower_reduction_clauses, lower_send_clauses): Likewise. gcc/c/ * c-parser.c (c_parser_omp_variable_list): Allow array sections for OMP_CLAUSE_REDUCTION. (c_parser_omp_clause_reduction): Compute element type even for arrays and array sections. (c_parser_omp_declare_reduction): STRIP_NOPS before checking for &omp_priv. * c-typeck.c (handle_omp_array_sections_1): Fix a comment typo. Handle OMP_CLAUSE_REDUCTION array sections. Report zero size array sections on OMP_CLAUSE_DEPEND. (handle_omp_array_sections): Use auto_vec for types, drop types.release () calls. Handle OMP_CLAUSE_REDUCTION array sections. (c_finish_omp_clauses): Handle OMP_CLAUSE_REDUCTION array sections and arrays. gcc/cp/ * parser.c (cp_parser_omp_var_list_no_open): Allow array sections for OMP_CLAUSE_REDUCTION. * semantics.c (omp_clause_decl_field, omp_note_field_privatization, omp_privatize_field): New functions. (omp_clause_printable_decl): Use omp_clause_decl_field, move earlier. (handle_omp_array_sections_1): Fix a comment typo. Handle OMP_CLAUSE_REDUCTION array sections. Report zero size array sections on OMP_CLAUSE_DEPEND. (handle_omp_array_sections): Handle OMP_CLAUSE_REDUCTION array sections. (finish_omp_reduction_clause): Handle OMP_CLAUSE_REDUCTION array sections and arrays. (finish_omp_clauses): Likewise. Use omp_note_field_privatization, omp_clause_decl_field and omp_privatize_field. gcc/c-family/ * c-omp.c (c_omp_split_clauses): Copy over also OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER. gcc/testsuite/ * gcc.dg/gomp/clause-1.c (foo): Remove one dg-error directive. * g++.dg/gomp/clause-3.C (foo): Likewise. * gcc.dg/gomp/reduction-1.c: New test. * c-c++-common/gomp/depend-3.c: New test. * c-c++-common/gomp/reduction-1.c: New test. * c-c++-common/gomp/udr-1.c: New test. libgomp/ * testsuite/libgomp.c/reduction-7.c: New test. * testsuite/libgomp.c/reduction-8.c: New test. * testsuite/libgomp.c/reduction-9.c: New test. * testsuite/libgomp.c/reduction-10.c: New test. * testsuite/libgomp.c++/taskloop-5.C (foo): Wrap #pragma omp parallel bodies into #pragma omp single. * testsuite/libgomp.c++/reduction-5.C: New test. * testsuite/libgomp.c++/reduction-6.C: New test. * testsuite/libgomp.c++/reduction-7.C: New test. * testsuite/libgomp.c++/reduction-8.C: New test. * testsuite/libgomp.c++/reduction-9.C: New test. * testsuite/libgomp.c++/reduction-10.C: New test. --- gcc/tree.c.jj 2015-05-19 18:56:50.000000000 +0200 +++ gcc/tree.c 2015-06-08 10:49:02.965545605 +0200 @@ -321,7 +321,7 @@ unsigned const char omp_clause_num_ops[] 1, /* OMP_CLAUSE_SHARED */ 1, /* OMP_CLAUSE_FIRSTPRIVATE */ 2, /* OMP_CLAUSE_LASTPRIVATE */ - 4, /* OMP_CLAUSE_REDUCTION */ + 5, /* OMP_CLAUSE_REDUCTION */ 1, /* OMP_CLAUSE_COPYIN */ 1, /* OMP_CLAUSE_COPYPRIVATE */ 3, /* OMP_CLAUSE_LINEAR */ @@ -11361,7 +11361,7 @@ walk_tree_1 (tree *tp, walk_tree_fn func case OMP_CLAUSE_REDUCTION: { int i; - for (i = 0; i < 4; i++) + for (i = 0; i < 5; i++) WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, i)); WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp)); } --- gcc/tree-core.h.jj 2015-05-06 17:04:52.000000000 +0200 +++ gcc/tree-core.h 2015-06-08 11:08:41.914555026 +0200 @@ -230,7 +230,10 @@ enum omp_clause_code { Operand 2: OMP_CLAUSE_REDUCTION_MERGE: Stmt-list to merge private var into the shared one. Operand 3: OMP_CLAUSE_REDUCTION_PLACEHOLDER: A dummy VAR_DECL - placeholder used in OMP_CLAUSE_REDUCTION_{INIT,MERGE}. */ + placeholder used in OMP_CLAUSE_REDUCTION_{INIT,MERGE}. + Operand 4: OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER: Another dummy + VAR_DECL placeholder, used like the above for C/C++ array + reductions. */ OMP_CLAUSE_REDUCTION, /* OpenMP clause: copyin (variable_list). */ --- gcc/tree.h.jj 2015-05-21 11:12:09.000000000 +0200 +++ gcc/tree.h 2015-06-08 10:48:20.855190071 +0200 @@ -1458,6 +1458,8 @@ extern void protected_set_expr_location (OMP_CLAUSE_CHECK (NODE))->omp_clause.gimple_reduction_merge #define OMP_CLAUSE_REDUCTION_PLACEHOLDER(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_REDUCTION), 3) +#define OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_REDUCTION), 4) /* True if a REDUCTION clause may reference the original list item (omp_orig) in its OMP_CLAUSE_REDUCTION_{,GIMPLE_}INIT. */ --- gcc/tree-nested.c.jj 2015-05-06 18:01:30.000000000 +0200 +++ gcc/tree-nested.c 2015-06-08 11:22:30.655894530 +0200 @@ -1236,6 +1236,9 @@ convert_nonlocal_omp_clauses (tree *pcla = DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause)); DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause)) = info->context; + if (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause)) + DECL_CONTEXT (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause)) + = info->context; walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op, info, &OMP_CLAUSE_REDUCTION_GIMPLE_INIT (clause)); @@ -1244,6 +1247,9 @@ convert_nonlocal_omp_clauses (tree *pcla &OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (clause)); DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause)) = old_context; + if (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause)) + DECL_CONTEXT (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause)) + = old_context; } break; @@ -1881,6 +1887,9 @@ convert_local_omp_clauses (tree *pclause = DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause)); DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause)) = info->context; + if (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause)) + DECL_CONTEXT (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause)) + = info->context; walk_body (convert_local_reference_stmt, convert_local_reference_op, info, &OMP_CLAUSE_REDUCTION_GIMPLE_INIT (clause)); @@ -1889,6 +1898,9 @@ convert_local_omp_clauses (tree *pclause &OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (clause)); DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause)) = old_context; + if (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause)) + DECL_CONTEXT (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clause)) + = old_context; } break; --- gcc/gimplify.c.jj 2015-05-29 16:01:15.000000000 +0200 +++ gcc/gimplify.c 2015-06-10 17:57:35.278144016 +0200 @@ -5739,7 +5739,7 @@ omp_add_variable (struct gimplify_omp_ct if ((flags & GOVD_SHARED) == 0) { t = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (decl))); - if (TREE_CODE (t) != INTEGER_CST) + if (DECL_P (t)) omp_notice_variable (ctx, t, true); } } @@ -6129,6 +6129,22 @@ omp_no_lastprivate (struct gimplify_omp_ while (1); } +/* Callback for walk_tree to find a DECL_EXPR for the given DECL. */ + +static tree +find_decl_expr (tree *tp, int *walk_subtrees, void *data) +{ + tree t = *tp; + + /* If this node has been visited, unmark it and keep looking. */ + if (TREE_CODE (t) == DECL_EXPR && DECL_EXPR_DECL (t) == (tree) data) + return t; + + if (IS_TYPE_OR_DECL_P (t)) + *walk_subtrees = 0; + return NULL_TREE; +} + /* Scan the OMP clauses in *LIST_P, installing mappings into a new and previous omp contexts. */ @@ -6211,7 +6227,28 @@ gimplify_scan_omp_clauses (tree *list_p, case OMP_CLAUSE_REDUCTION: flags = GOVD_REDUCTION | GOVD_SEEN | GOVD_EXPLICIT; check_non_private = "reduction"; - goto do_add; + decl = OMP_CLAUSE_DECL (c); + if (TREE_CODE (decl) == MEM_REF) + { + tree type = TREE_TYPE (decl); + if (gimplify_expr (&TYPE_MAX_VALUE (TYPE_DOMAIN (type)), pre_p, + NULL, is_gimple_val, fb_rvalue) == GS_ERROR) + { + remove = true; + break; + } + tree v = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); + if (DECL_P (v)) + { + omp_firstprivatize_variable (ctx, v); + omp_notice_variable (ctx, v, true); + } + decl = TREE_OPERAND (decl, 0); + if (TREE_CODE (decl) == ADDR_EXPR + || TREE_CODE (decl) == INDIRECT_REF) + decl = TREE_OPERAND (decl, 0); + } + goto do_add_decl; case OMP_CLAUSE_LINEAR: if (gimplify_expr (&OMP_CLAUSE_LINEAR_STEP (c), pre_p, NULL, is_gimple_val, fb_rvalue) == GS_ERROR) @@ -6371,6 +6408,7 @@ gimplify_scan_omp_clauses (tree *list_p, do_add: decl = OMP_CLAUSE_DECL (c); + do_add_decl: if (error_operand_p (decl)) { remove = true; @@ -6393,6 +6431,14 @@ gimplify_scan_omp_clauses (tree *list_p, { omp_add_variable (ctx, OMP_CLAUSE_REDUCTION_PLACEHOLDER (c), GOVD_LOCAL | GOVD_SEEN); + if (OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c) + && walk_tree (&OMP_CLAUSE_REDUCTION_INIT (c), + find_decl_expr, + OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c), + NULL) == NULL_TREE) + omp_add_variable (ctx, + OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c), + GOVD_LOCAL | GOVD_SEEN); gimplify_omp_ctxp = ctx; push_gimplify_context (); @@ -6496,6 +6542,11 @@ gimplify_scan_omp_clauses (tree *list_p, omp_notice_variable (outer_ctx, decl, true); if (check_non_private && region_type == ORT_WORKSHARE + && (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION + || decl == OMP_CLAUSE_DECL (c) + || (TREE_CODE (OMP_CLAUSE_DECL (c)) == MEM_REF + && (TREE_CODE (TREE_OPERAND (OMP_CLAUSE_DECL (c), 0)) + == ADDR_EXPR))) && omp_check_private (ctx, decl, false)) { error ("%s variable %qE is private in outer context", --- gcc/omp-low.c.jj 2015-06-02 14:22:19.000000000 +0200 +++ gcc/omp-low.c 2015-06-09 19:56:41.821729677 +0200 @@ -1856,6 +1856,27 @@ scan_sharing_clauses (tree clauses, omp_ OMP_CLAUSE_SET_CODE (c, OMP_CLAUSE_FIRSTPRIVATE); goto do_private; + case OMP_CLAUSE_REDUCTION: + decl = OMP_CLAUSE_DECL (c); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + && TREE_CODE (decl) == MEM_REF) + { + tree t = TREE_OPERAND (decl, 0); + if (TREE_CODE (t) == INDIRECT_REF + || TREE_CODE (t) == ADDR_EXPR) + t = TREE_OPERAND (t, 0); + install_var_local (t, ctx); + if (is_taskreg_ctx (ctx) + && !is_global_var (maybe_lookup_decl_in_outer_ctx (t, ctx)) + && !is_variable_sized (t)) + { + by_ref = use_pointer_for_field (t, ctx); + install_var_field (t, by_ref, 3, ctx); + } + break; + } + goto do_private; + case OMP_CLAUSE_LASTPRIVATE: /* Let the corresponding firstprivate clause create the variable. */ @@ -1870,7 +1891,6 @@ scan_sharing_clauses (tree clauses, omp_ break; } /* FALLTHRU */ - case OMP_CLAUSE_REDUCTION: case OMP_CLAUSE_LINEAR: decl = OMP_CLAUSE_DECL (c); do_private: @@ -2102,7 +2122,6 @@ scan_sharing_clauses (tree clauses, omp_ } /* FALLTHRU */ case OMP_CLAUSE_PRIVATE: - case OMP_CLAUSE_REDUCTION: case OMP_CLAUSE_LINEAR: decl = OMP_CLAUSE_DECL (c); if (is_variable_sized (decl)) @@ -2110,11 +2129,20 @@ scan_sharing_clauses (tree clauses, omp_ fixup_remapped_decl (decl, ctx, OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE && OMP_CLAUSE_PRIVATE_DEBUG (c)); - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION - && OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR + && OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c)) scan_array_reductions = true; - else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR - && OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c)) + break; + + case OMP_CLAUSE_REDUCTION: + decl = OMP_CLAUSE_DECL (c); + if (TREE_CODE (decl) != MEM_REF) + { + if (is_variable_sized (decl)) + install_var_local (decl, ctx); + fixup_remapped_decl (decl, ctx, false); + } + if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) scan_array_reductions = true; break; @@ -3861,13 +3889,17 @@ lower_rec_input_clauses (tree clauses, g if (OMP_CLAUSE_LINEAR_ARRAY (c)) max_vf = 1; /* FALLTHRU */ - case OMP_CLAUSE_REDUCTION: case OMP_CLAUSE_PRIVATE: case OMP_CLAUSE_FIRSTPRIVATE: case OMP_CLAUSE_LASTPRIVATE: if (is_variable_sized (OMP_CLAUSE_DECL (c))) max_vf = 1; break; + case OMP_CLAUSE_REDUCTION: + if (TREE_CODE (OMP_CLAUSE_DECL (c)) == MEM_REF + || is_variable_sized (OMP_CLAUSE_DECL (c))) + max_vf = 1; + break; default: continue; } @@ -3970,6 +4002,22 @@ lower_rec_input_clauses (tree clauses, g } new_var = var = OMP_CLAUSE_DECL (c); + if (c_kind == OMP_CLAUSE_REDUCTION && TREE_CODE (var) == MEM_REF) + { + var = TREE_OPERAND (var, 0); + if (TREE_CODE (var) == INDIRECT_REF + || TREE_CODE (var) == ADDR_EXPR) + var = TREE_OPERAND (var, 0); + if (is_variable_sized (var)) + { + gcc_assert (DECL_HAS_VALUE_EXPR_P (var)); + var = DECL_VALUE_EXPR (var); + gcc_assert (TREE_CODE (var) == INDIRECT_REF); + var = TREE_OPERAND (var, 0); + gcc_assert (DECL_P (var)); + } + new_var = var; + } if (c_kind != OMP_CLAUSE_COPYIN) new_var = lookup_decl (var, ctx); @@ -3978,6 +4026,236 @@ lower_rec_input_clauses (tree clauses, g if (pass != 0) continue; } + /* C/C++ array section reductions. */ + else if (c_kind == OMP_CLAUSE_REDUCTION + && var != OMP_CLAUSE_DECL (c)) + { + if (pass == 0) + continue; + + tree orig_var = TREE_OPERAND (OMP_CLAUSE_DECL (c), 0); + if (TREE_CODE (orig_var) == INDIRECT_REF + || TREE_CODE (orig_var) == ADDR_EXPR) + orig_var = TREE_OPERAND (orig_var, 0); + tree d = OMP_CLAUSE_DECL (c); + tree type = TREE_TYPE (d); + gcc_assert (TREE_CODE (type) == ARRAY_TYPE); + tree v = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); + const char *name = NULL; + if (DECL_NAME (orig_var)) + name = IDENTIFIER_POINTER (DECL_NAME (orig_var)); + if (TREE_CONSTANT (v)) + { + x = create_tmp_var_raw (type, name); + gimple_add_tmp_var (x); + TREE_ADDRESSABLE (x) = 1; + x = build_fold_addr_expr_loc (clause_loc, x); + } + else + { + tree atmp = builtin_decl_explicit (BUILT_IN_ALLOCA); + tree t = maybe_lookup_decl (v, ctx); + if (t) + v = t; + else + v = maybe_lookup_decl_in_outer_ctx (v, ctx); + gimplify_expr (&v, ilist, NULL, is_gimple_val, fb_rvalue); + t = fold_build2_loc (clause_loc, PLUS_EXPR, + TREE_TYPE (v), v, + build_int_cst (TREE_TYPE (v), 1)); + t = fold_build2_loc (clause_loc, MULT_EXPR, + TREE_TYPE (v), t, + TYPE_SIZE_UNIT (TREE_TYPE (type))); + x = build_call_expr_loc (clause_loc, atmp, 1, t); + } + + tree ptype = build_pointer_type (TREE_TYPE (type)); + x = fold_convert_loc (clause_loc, ptype, x); + tree y = create_tmp_var (ptype, name); + gimplify_assign (y, x, ilist); + x = y; + if (TREE_CODE (TREE_OPERAND (d, 0)) == ADDR_EXPR) + { + if (orig_var != var) + { + gcc_assert (is_variable_sized (orig_var)); + x = fold_convert_loc (clause_loc, TREE_TYPE (new_var), + x); + gimplify_assign (new_var, x, ilist); + tree new_orig_var = lookup_decl (orig_var, ctx); + tree t = build_fold_indirect_ref (new_var); + DECL_IGNORED_P (new_var) = 0; + TREE_THIS_NOTRAP (t); + SET_DECL_VALUE_EXPR (new_orig_var, t); + DECL_HAS_VALUE_EXPR_P (new_orig_var) = 1; + } + else + { + x = build2 (MEM_REF, TREE_TYPE (new_var), x, + build_int_cst (ptype, 0)); + SET_DECL_VALUE_EXPR (new_var, x); + DECL_HAS_VALUE_EXPR_P (new_var) = 1; + } + } + else + { + gcc_assert (orig_var == var); + if (TREE_CODE (TREE_OPERAND (d, 0)) == INDIRECT_REF) + { + x = create_tmp_var (ptype, name); + TREE_ADDRESSABLE (x) = 1; + gimplify_assign (x, y, ilist); + x = build_fold_addr_expr_loc (clause_loc, x); + } + x = fold_convert_loc (clause_loc, TREE_TYPE (new_var), x); + gimplify_assign (new_var, x, ilist); + } + tree y1 = create_tmp_var (ptype, NULL); + gimplify_assign (y1, y, ilist); + tree i2 = NULL_TREE, y2 = NULL_TREE; + tree body2 = NULL_TREE, end2 = NULL_TREE; + tree y3 = NULL_TREE, y4 = NULL_TREE; + if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) || is_simd) + { + y2 = create_tmp_var (ptype, NULL); + gimplify_assign (y2, y, ilist); + tree ref = build_outer_var_ref (var, ctx); + /* For ref build_outer_var_ref already performs this. */ + if (TREE_CODE (TREE_OPERAND (d, 0)) == INDIRECT_REF) + gcc_assert (is_reference (var)); + else if (TREE_CODE (TREE_OPERAND (d, 0)) == ADDR_EXPR) + ref = build_fold_addr_expr (ref); + else if (is_reference (var)) + ref = build_fold_addr_expr (ref); + ref = fold_convert_loc (clause_loc, ptype, ref); + if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) + && OMP_CLAUSE_REDUCTION_OMP_ORIG_REF (c)) + { + y3 = create_tmp_var (ptype, NULL); + gimplify_assign (y3, unshare_expr (ref), ilist); + } + if (is_simd) + { + y4 = create_tmp_var (ptype, NULL); + gimplify_assign (y4, ref, dlist); + } + } + tree i = create_tmp_var (TREE_TYPE (v), NULL); + gimplify_assign (i, build_int_cst (TREE_TYPE (v), 0), ilist); + tree body = create_artificial_label (UNKNOWN_LOCATION); + tree end = create_artificial_label (UNKNOWN_LOCATION); + gimple_seq_add_stmt (ilist, gimple_build_label (body)); + if (y2) + { + i2 = create_tmp_var (TREE_TYPE (v), NULL); + gimplify_assign (i2, build_int_cst (TREE_TYPE (v), 0), dlist); + body2 = create_artificial_label (UNKNOWN_LOCATION); + end2 = create_artificial_label (UNKNOWN_LOCATION); + gimple_seq_add_stmt (dlist, gimple_build_label (body2)); + } + if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) + { + tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c); + tree decl_placeholder + = OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c); + SET_DECL_VALUE_EXPR (decl_placeholder, + build_simple_mem_ref (y1)); + DECL_HAS_VALUE_EXPR_P (decl_placeholder) = 1; + SET_DECL_VALUE_EXPR (placeholder, + y3 ? build_simple_mem_ref (y3) + : error_mark_node); + DECL_HAS_VALUE_EXPR_P (placeholder) = 1; + x = lang_hooks.decls.omp_clause_default_ctor + (c, build_simple_mem_ref (y1), + y3 ? build_simple_mem_ref (y3) : NULL_TREE); + if (x) + gimplify_and_add (x, ilist); + if (OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c)) + { + gimple_seq tseq = OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c); + lower_omp (&tseq, ctx); + gimple_seq_add_seq (ilist, tseq); + } + OMP_CLAUSE_REDUCTION_GIMPLE_INIT (c) = NULL; + if (is_simd) + { + SET_DECL_VALUE_EXPR (decl_placeholder, + build_simple_mem_ref (y2)); + SET_DECL_VALUE_EXPR (placeholder, + build_simple_mem_ref (y4)); + gimple_seq tseq = OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c); + lower_omp (&tseq, ctx); + gimple_seq_add_seq (dlist, tseq); + OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c) = NULL; + } + DECL_HAS_VALUE_EXPR_P (placeholder) = 0; + DECL_HAS_VALUE_EXPR_P (decl_placeholder) = 0; + x = lang_hooks.decls.omp_clause_dtor + (c, build_simple_mem_ref (y2)); + if (x) + { + gimple_seq tseq = NULL; + dtor = x; + gimplify_stmt (&dtor, &tseq); + gimple_seq_add_seq (dlist, tseq); + } + } + else + { + x = omp_reduction_init (c, TREE_TYPE (type)); + enum tree_code code = OMP_CLAUSE_REDUCTION_CODE (c); + + /* reduction(-:var) sums up the partial results, so it + acts identically to reduction(+:var). */ + if (code == MINUS_EXPR) + code = PLUS_EXPR; + + gimplify_assign (build_simple_mem_ref (y1), x, ilist); + if (is_simd) + { + x = build2 (code, TREE_TYPE (type), + build_simple_mem_ref (y4), + build_simple_mem_ref (y2)); + gimplify_assign (build_simple_mem_ref (y4), x, dlist); + } + } + gimple g + = gimple_build_assign (y1, POINTER_PLUS_EXPR, y1, + TYPE_SIZE_UNIT (TREE_TYPE (type))); + gimple_seq_add_stmt (ilist, g); + if (y3) + { + g = gimple_build_assign (y3, POINTER_PLUS_EXPR, y3, + TYPE_SIZE_UNIT (TREE_TYPE (type))); + gimple_seq_add_stmt (ilist, g); + } + g = gimple_build_assign (i, PLUS_EXPR, i, + build_int_cst (TREE_TYPE (i), 1)); + gimple_seq_add_stmt (ilist, g); + g = gimple_build_cond (LE_EXPR, i, v, body, end); + gimple_seq_add_stmt (ilist, g); + gimple_seq_add_stmt (ilist, gimple_build_label (end)); + if (y2) + { + g = gimple_build_assign (y2, POINTER_PLUS_EXPR, y2, + TYPE_SIZE_UNIT (TREE_TYPE (type))); + gimple_seq_add_stmt (dlist, g); + if (y4) + { + g = gimple_build_assign + (y4, POINTER_PLUS_EXPR, y4, + TYPE_SIZE_UNIT (TREE_TYPE (type))); + gimple_seq_add_stmt (dlist, g); + } + g = gimple_build_assign (i2, PLUS_EXPR, i2, + build_int_cst (TREE_TYPE (i2), 1)); + gimple_seq_add_stmt (dlist, g); + g = gimple_build_cond (LE_EXPR, i2, v, body2, end2); + gimple_seq_add_stmt (dlist, g); + gimple_seq_add_stmt (dlist, gimple_build_label (end2)); + } + continue; + } else if (is_variable_sized (var)) { /* For variable sized types, we need to allocate the @@ -4770,7 +5048,8 @@ lower_reduction_clauses (tree clauses, g for (c = clauses; c && count < 2; c = OMP_CLAUSE_CHAIN (c)) if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) { - if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) + if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) + || TREE_CODE (OMP_CLAUSE_DECL (c)) == MEM_REF) { /* Never use OMP_ATOMIC for array reductions or UDRs. */ count = -1; @@ -4795,16 +5074,32 @@ lower_reduction_clauses (tree clauses, g for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c)) { - tree var, ref, new_var; + tree var, ref, new_var, orig_var; enum tree_code code; location_t clause_loc = OMP_CLAUSE_LOCATION (c); if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION) continue; - var = OMP_CLAUSE_DECL (c); + orig_var = var = OMP_CLAUSE_DECL (c); + if (TREE_CODE (var) == MEM_REF) + { + var = TREE_OPERAND (var, 0); + if (TREE_CODE (var) == INDIRECT_REF + || TREE_CODE (var) == ADDR_EXPR) + var = TREE_OPERAND (var, 0); + orig_var = var; + if (is_variable_sized (var)) + { + gcc_assert (DECL_HAS_VALUE_EXPR_P (var)); + var = DECL_VALUE_EXPR (var); + gcc_assert (TREE_CODE (var) == INDIRECT_REF); + var = TREE_OPERAND (var, 0); + gcc_assert (DECL_P (var)); + } + } new_var = lookup_decl (var, ctx); - if (is_reference (var)) + if (var == OMP_CLAUSE_DECL (c) && is_reference (var)) new_var = build_simple_mem_ref_loc (clause_loc, new_var); ref = build_outer_var_ref (var, ctx); code = OMP_CLAUSE_REDUCTION_CODE (c); @@ -4831,6 +5126,92 @@ lower_reduction_clauses (tree clauses, g gimplify_and_add (x, stmt_seqp); return; } + else if (TREE_CODE (OMP_CLAUSE_DECL (c)) == MEM_REF) + { + tree d = OMP_CLAUSE_DECL (c); + tree type = TREE_TYPE (d); + tree v = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); + tree i = create_tmp_var (TREE_TYPE (v), NULL); + tree ptype = build_pointer_type (TREE_TYPE (type)); + /* For ref build_outer_var_ref already performs this, so + only new_var needs a dereference. */ + if (TREE_CODE (TREE_OPERAND (d, 0)) == INDIRECT_REF) + { + new_var = build_simple_mem_ref_loc (clause_loc, new_var); + gcc_assert (is_reference (var) && var == orig_var); + } + else if (TREE_CODE (TREE_OPERAND (d, 0)) == ADDR_EXPR) + { + if (orig_var == var) + { + new_var = build_fold_addr_expr (new_var); + ref = build_fold_addr_expr (ref); + } + } + else + { + gcc_assert (orig_var == var); + if (is_reference (var)) + ref = build_fold_addr_expr (ref); + } + if (DECL_P (v)) + { + tree t = maybe_lookup_decl (v, ctx); + if (t) + v = t; + else + v = maybe_lookup_decl_in_outer_ctx (v, ctx); + gimplify_expr (&v, stmt_seqp, NULL, is_gimple_val, fb_rvalue); + } + new_var = fold_convert_loc (clause_loc, ptype, new_var); + ref = fold_convert_loc (clause_loc, ptype, ref); + tree m = create_tmp_var (ptype, NULL); + gimplify_assign (m, new_var, stmt_seqp); + new_var = m; + m = create_tmp_var (ptype, NULL); + gimplify_assign (m, ref, stmt_seqp); + ref = m; + gimplify_assign (i, build_int_cst (TREE_TYPE (v), 0), stmt_seqp); + tree body = create_artificial_label (UNKNOWN_LOCATION); + tree end = create_artificial_label (UNKNOWN_LOCATION); + gimple_seq_add_stmt (&sub_seq, gimple_build_label (body)); + tree priv = build_simple_mem_ref_loc (clause_loc, new_var); + tree out = build_simple_mem_ref_loc (clause_loc, ref); + if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) + { + tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c); + tree decl_placeholder + = OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c); + SET_DECL_VALUE_EXPR (placeholder, out); + DECL_HAS_VALUE_EXPR_P (placeholder) = 1; + SET_DECL_VALUE_EXPR (decl_placeholder, priv); + DECL_HAS_VALUE_EXPR_P (decl_placeholder) = 1; + lower_omp (&OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c), ctx); + gimple_seq_add_seq (&sub_seq, + OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c)); + OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (c) = NULL; + OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = NULL; + OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c) = NULL; + } + else + { + x = build2 (code, TREE_TYPE (out), out, priv); + out = unshare_expr (out); + gimplify_assign (out, x, &sub_seq); + } + gimple g = gimple_build_assign (new_var, POINTER_PLUS_EXPR, new_var, + TYPE_SIZE_UNIT (TREE_TYPE (type))); + gimple_seq_add_stmt (&sub_seq, g); + g = gimple_build_assign (ref, POINTER_PLUS_EXPR, ref, + TYPE_SIZE_UNIT (TREE_TYPE (type))); + gimple_seq_add_stmt (&sub_seq, g); + g = gimple_build_assign (i, PLUS_EXPR, i, + build_int_cst (TREE_TYPE (i), 1)); + gimple_seq_add_stmt (&sub_seq, g); + g = gimple_build_cond (LE_EXPR, i, v, body, end); + gimple_seq_add_stmt (&sub_seq, g); + gimple_seq_add_stmt (&sub_seq, gimple_build_label (end)); + } else if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) { tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c); @@ -4966,6 +5347,16 @@ lower_send_clauses (tree clauses, gimple } val = OMP_CLAUSE_DECL (c); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + && TREE_CODE (val) == MEM_REF) + { + val = TREE_OPERAND (val, 0); + if (TREE_CODE (val) == INDIRECT_REF + || TREE_CODE (val) == ADDR_EXPR) + val = TREE_OPERAND (val, 0); + if (is_variable_sized (val)) + continue; + } var = lookup_decl_in_outer_ctx (val, ctx); if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_COPYIN @@ -5001,7 +5392,9 @@ lower_send_clauses (tree clauses, gimple continue; } - if (is_variable_sized (val)) + if ((OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION + || val == OMP_CLAUSE_DECL (c)) + && is_variable_sized (val)) continue; by_ref = use_pointer_for_field (val, NULL); @@ -5031,7 +5424,10 @@ lower_send_clauses (tree clauses, gimple case OMP_CLAUSE_REDUCTION: do_in = true; - do_out = !(by_ref || is_reference (val)); + if (val == OMP_CLAUSE_DECL (c)) + do_out = !(by_ref || is_reference (val)); + else + by_ref = TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE; break; default: --- gcc/c/c-parser.c.jj 2015-05-26 19:12:30.000000000 +0200 +++ gcc/c/c-parser.c 2015-06-10 14:52:06.258288807 +0200 @@ -10191,6 +10191,7 @@ c_parser_omp_variable_list (c_parser *pa case OMP_CLAUSE_FROM: case OMP_CLAUSE_TO: case OMP_CLAUSE_DEPEND: + case OMP_CLAUSE_REDUCTION: while (c_parser_next_token_is (parser, CPP_OPEN_SQUARE)) { tree low_bound = NULL_TREE, length = NULL_TREE; @@ -11067,7 +11068,27 @@ c_parser_omp_clause_reduction (c_parser OMP_CLAUSE_REDUCTION, list); for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) { - tree type = TREE_TYPE (OMP_CLAUSE_DECL (c)); + tree d = OMP_CLAUSE_DECL (c), type; + if (TREE_CODE (d) != TREE_LIST) + type = TREE_TYPE (d); + else + { + int cnt = 0; + tree t; + for (t = d; TREE_CODE (t) == TREE_LIST; t = TREE_CHAIN (t)) + cnt++; + type = TREE_TYPE (t); + while (cnt > 0) + { + if (TREE_CODE (type) != POINTER_TYPE + && TREE_CODE (type) != ARRAY_TYPE) + break; + type = TREE_TYPE (type); + cnt--; + } + } + while (TREE_CODE (type) == ARRAY_TYPE) + type = TREE_TYPE (type); OMP_CLAUSE_REDUCTION_CODE (c) = code; if (code == ERROR_MARK || !(INTEGRAL_TYPE_P (type) @@ -15084,9 +15105,13 @@ c_parser_omp_declare_reduction (c_parser int j; tree c = initializer.value; for (j = 0; j < call_expr_nargs (c); j++) - if (TREE_CODE (CALL_EXPR_ARG (c, j)) == ADDR_EXPR - && TREE_OPERAND (CALL_EXPR_ARG (c, j), 0) == omp_priv) - break; + { + tree a = CALL_EXPR_ARG (c, j); + STRIP_NOPS (a); + if (TREE_CODE (a) == ADDR_EXPR + && TREE_OPERAND (a, 0) == omp_priv) + break; + } if (j == call_expr_nargs (c)) error ("one of the initializer call arguments should be " "%<&omp_priv%>"); --- gcc/c/c-typeck.c.jj 2015-05-19 18:56:47.000000000 +0200 +++ gcc/c/c-typeck.c 2015-06-10 15:23:36.445054654 +0200 @@ -11591,7 +11591,7 @@ c_finish_omp_cancellation_point (locatio map(a[:b][2:1][:c][:2][:d][e:f][2:5]) FIRST_NON_ONE will be 3, array-section-subscript [:b], [2:1] and [:c] all are or may have length of 1, array-section-subscript [:2] is the - first one knonwn not to have length 1. For array-section-subscript + first one known not to have length 1. For array-section-subscript <= FIRST_NON_ONE we diagnose non-contiguous arrays if low bound isn't 0 or length isn't the array domain max + 1, for > FIRST_NON_ONE we can if MAYBE_ZERO_LEN is false. MAYBE_ZERO_LEN will be true in the above @@ -11671,11 +11671,32 @@ handle_omp_array_sections_1 (tree c, tre if (length != NULL_TREE) { if (!integer_nonzerop (length)) - maybe_zero_len = true; + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + { + if (integer_zerop (length)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "zero length array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + } + else + maybe_zero_len = true; + } if (first_non_one == types.length () && (TREE_CODE (length) != INTEGER_CST || integer_onep (length))) first_non_one++; } + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + && !integer_zerop (low_bound)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%<reduction%> array section has to be zero-based"); + return error_mark_node; + } if (TREE_CODE (type) == ARRAY_TYPE) { if (length == NULL_TREE @@ -11723,7 +11744,17 @@ handle_omp_array_sections_1 (tree c, tre return error_mark_node; } if (tree_int_cst_equal (size, low_bound)) - maybe_zero_len = true; + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + { + error_at (OMP_CLAUSE_LOCATION (c), + "zero length array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + maybe_zero_len = true; + } else if (length == NULL_TREE && first_non_one == types.length () && tree_int_cst_equal @@ -11733,7 +11764,9 @@ handle_omp_array_sections_1 (tree c, tre } else if (length == NULL_TREE) { - maybe_zero_len = true; + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION) + maybe_zero_len = true; if (first_non_one == types.length ()) first_non_one++; } @@ -11767,7 +11800,9 @@ handle_omp_array_sections_1 (tree c, tre } else if (length == NULL_TREE) { - maybe_zero_len = true; + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION) + maybe_zero_len = true; if (first_non_one == types.length ()) first_non_one++; } @@ -11828,24 +11863,17 @@ handle_omp_array_sections (tree c) { bool maybe_zero_len = false; unsigned int first_non_one = 0; - vec<tree> types = vNULL; + auto_vec<tree, 10> types; tree first = handle_omp_array_sections_1 (c, OMP_CLAUSE_DECL (c), types, maybe_zero_len, first_non_one); if (first == error_mark_node) - { - types.release (); - return true; - } + return true; if (first == NULL_TREE) - { - types.release (); - return false; - } + return false; if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND) { tree t = OMP_CLAUSE_DECL (c); tree tem = NULL_TREE; - types.release (); /* Need to evaluate side effects in the length expressions if any. */ while (TREE_CODE (t) == TREE_LIST) @@ -11915,7 +11943,6 @@ handle_omp_array_sections (tree c) "array section is not contiguous in %qs " "clause", omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - types.release (); return true; } } @@ -11934,7 +11961,9 @@ handle_omp_array_sections (tree c) { tree l; - if (i > first_non_one && length && integer_nonzerop (length)) + if (i > first_non_one + && ((length && integer_nonzerop (length)) + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)) continue; if (length) l = fold_convert (sizetype, length); @@ -11959,6 +11988,22 @@ handle_omp_array_sections (tree c) else if (size == NULL_TREE) { size = size_in_bytes (TREE_TYPE (types[i])); + tree eltype = TREE_TYPE (types[num - 1]); + while (TREE_CODE (eltype) == ARRAY_TYPE) + eltype = TREE_TYPE (eltype); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + { + if (integer_zerop (size) + || integer_zerop (size_in_bytes (eltype))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "zero length array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + size = size_binop (EXACT_DIV_EXPR, size, + size_in_bytes (eltype)); + } size = size_binop (MULT_EXPR, size, l); if (condition) size = fold_build3 (COND_EXPR, sizetype, condition, @@ -11968,9 +12013,24 @@ handle_omp_array_sections (tree c) size = size_binop (MULT_EXPR, size, l); } } - types.release (); if (side_effects) size = build2 (COMPOUND_EXPR, sizetype, side_effects, size); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + { + size = size_binop (MINUS_EXPR, size, size_one_node); + size = c_fully_fold (size, false, NULL); + tree index_type = build_index_type (size); + tree eltype = TREE_TYPE (first); + while (TREE_CODE (eltype) == ARRAY_TYPE) + eltype = TREE_TYPE (eltype); + tree type = build_array_type (eltype, index_type); + tree ptype = build_pointer_type (eltype); + if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + t = build_fold_addr_expr (t); + t = build2 (MEM_REF, type, t, build_int_cst (ptype, 0)); + OMP_CLAUSE_DECL (c) = t; + return false; + } first = c_fully_fold (first, false, NULL); OMP_CLAUSE_DECL (c) = first; if (size) @@ -12050,7 +12110,7 @@ c_finish_omp_clauses (tree clauses) { bitmap_head generic_head, firstprivate_head, lastprivate_head; bitmap_head aligned_head; - tree c, t, *pc; + tree c, t, type, *pc; tree simdlen = NULL_TREE, safelen = NULL_TREE; bool branch_seen = false; bool copyprivate_seen = false; @@ -12082,9 +12142,61 @@ c_finish_omp_clauses (tree clauses) case OMP_CLAUSE_REDUCTION: need_implicitly_determined = true; t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) == TREE_LIST) + { + if (handle_omp_array_sections (c)) + { + remove = true; + break; + } + + t = OMP_CLAUSE_DECL (c); + } + t = require_complete_type (t); + if (t == error_mark_node) + { + remove = true; + break; + } + type = TREE_TYPE (t); + if (TREE_CODE (t) == MEM_REF) + type = TREE_TYPE (type); + if (TREE_CODE (type) == ARRAY_TYPE) + { + tree oatype = type; + gcc_assert (TREE_CODE (t) != MEM_REF); + while (TREE_CODE (type) == ARRAY_TYPE) + type = TREE_TYPE (type); + if (integer_zerop (TYPE_SIZE_UNIT (type))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD in %<reduction%> clause is a zero size array", + t); + remove = true; + break; + } + tree size = size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (oatype), + TYPE_SIZE_UNIT (type)); + if (integer_zerop (size)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD in %<reduction%> clause is a zero size array", + t); + remove = true; + break; + } + size = size_binop (MINUS_EXPR, size, size_one_node); + tree index_type = build_index_type (size); + tree atype = build_array_type (type, index_type); + tree ptype = build_pointer_type (type); + if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + t = build_fold_addr_expr (t); + t = build2 (MEM_REF, atype, t, build_int_cst (ptype, 0)); + OMP_CLAUSE_DECL (c) = t; + } if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) == NULL_TREE - && (FLOAT_TYPE_P (TREE_TYPE (t)) - || TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE)) + && (FLOAT_TYPE_P (type) + || TREE_CODE (type) == COMPLEX_TYPE)) { enum tree_code r_code = OMP_CLAUSE_REDUCTION_CODE (c); const char *r_name = NULL; @@ -12096,11 +12208,11 @@ c_finish_omp_clauses (tree clauses) case MINUS_EXPR: break; case MIN_EXPR: - if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE) + if (TREE_CODE (type) == COMPLEX_TYPE) r_name = "min"; break; case MAX_EXPR: - if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE) + if (TREE_CODE (type) == COMPLEX_TYPE) r_name = "max"; break; case BIT_AND_EXPR: @@ -12113,11 +12225,11 @@ c_finish_omp_clauses (tree clauses) r_name = "|"; break; case TRUTH_ANDIF_EXPR: - if (FLOAT_TYPE_P (TREE_TYPE (t))) + if (FLOAT_TYPE_P (type)) r_name = "&&"; break; case TRUTH_ORIF_EXPR: - if (FLOAT_TYPE_P (TREE_TYPE (t))) + if (FLOAT_TYPE_P (type)) r_name = "||"; break; default: @@ -12135,37 +12247,49 @@ c_finish_omp_clauses (tree clauses) else if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) == error_mark_node) { error_at (OMP_CLAUSE_LOCATION (c), - "user defined reduction not found for %qD", t); + "user defined reduction not found for %qE", t); remove = true; break; } else if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) { tree list = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c); - tree type = TYPE_MAIN_VARIANT (TREE_TYPE (t)); + type = TYPE_MAIN_VARIANT (type); tree placeholder = build_decl (OMP_CLAUSE_LOCATION (c), VAR_DECL, NULL_TREE, type); + tree decl_placeholder = NULL_TREE; OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = placeholder; DECL_ARTIFICIAL (placeholder) = 1; DECL_IGNORED_P (placeholder) = 1; + if (TREE_CODE (t) == MEM_REF) + { + decl_placeholder = build_decl (OMP_CLAUSE_LOCATION (c), + VAR_DECL, NULL_TREE, type); + OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c) = decl_placeholder; + DECL_ARTIFICIAL (decl_placeholder) = 1; + DECL_IGNORED_P (decl_placeholder) = 1; + } if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 0))) c_mark_addressable (placeholder); if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 1))) - c_mark_addressable (OMP_CLAUSE_DECL (c)); + c_mark_addressable (decl_placeholder ? decl_placeholder + : OMP_CLAUSE_DECL (c)); OMP_CLAUSE_REDUCTION_MERGE (c) = c_clone_omp_udr (TREE_VEC_ELT (list, 2), TREE_VEC_ELT (list, 0), TREE_VEC_ELT (list, 1), - OMP_CLAUSE_DECL (c), placeholder); + decl_placeholder ? decl_placeholder + : OMP_CLAUSE_DECL (c), placeholder); OMP_CLAUSE_REDUCTION_MERGE (c) = build3_loc (OMP_CLAUSE_LOCATION (c), BIND_EXPR, void_type_node, NULL_TREE, - OMP_CLAUSE_REDUCTION_MERGE (c), NULL_TREE); + OMP_CLAUSE_REDUCTION_MERGE (c), NULL_TREE); TREE_SIDE_EFFECTS (OMP_CLAUSE_REDUCTION_MERGE (c)) = 1; if (TREE_VEC_LENGTH (list) == 6) { if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 3))) - c_mark_addressable (OMP_CLAUSE_DECL (c)); + c_mark_addressable (decl_placeholder ? decl_placeholder + : OMP_CLAUSE_DECL (c)); if (TREE_ADDRESSABLE (TREE_VEC_ELT (list, 4))) c_mark_addressable (placeholder); tree init = TREE_VEC_ELT (list, 5); @@ -12174,11 +12298,15 @@ c_finish_omp_clauses (tree clauses) OMP_CLAUSE_REDUCTION_INIT (c) = c_clone_omp_udr (init, TREE_VEC_ELT (list, 4), TREE_VEC_ELT (list, 3), - OMP_CLAUSE_DECL (c), placeholder); + decl_placeholder ? decl_placeholder + : OMP_CLAUSE_DECL (c), placeholder); if (TREE_VEC_ELT (list, 5) == error_mark_node) - OMP_CLAUSE_REDUCTION_INIT (c) - = build2 (INIT_EXPR, TREE_TYPE (t), t, - OMP_CLAUSE_REDUCTION_INIT (c)); + { + tree v = decl_placeholder ? decl_placeholder : t; + OMP_CLAUSE_REDUCTION_INIT (c) + = build2 (INIT_EXPR, TREE_TYPE (v), v, + OMP_CLAUSE_REDUCTION_INIT (c)); + } if (walk_tree (&OMP_CLAUSE_REDUCTION_INIT (c), c_find_omp_placeholder_r, placeholder, NULL)) @@ -12187,12 +12315,13 @@ c_finish_omp_clauses (tree clauses) else { tree init; - if (AGGREGATE_TYPE_P (TREE_TYPE (t))) - init = build_constructor (TREE_TYPE (t), NULL); + tree v = decl_placeholder ? decl_placeholder : t; + if (AGGREGATE_TYPE_P (TREE_TYPE (v))) + init = build_constructor (TREE_TYPE (v), NULL); else - init = fold_convert (TREE_TYPE (t), integer_zero_node); + init = fold_convert (TREE_TYPE (v), integer_zero_node); OMP_CLAUSE_REDUCTION_INIT (c) - = build2 (INIT_EXPR, TREE_TYPE (t), t, init); + = build2 (INIT_EXPR, TREE_TYPE (v), v, init); } OMP_CLAUSE_REDUCTION_INIT (c) = build3_loc (OMP_CLAUSE_LOCATION (c), BIND_EXPR, @@ -12200,7 +12329,22 @@ c_finish_omp_clauses (tree clauses) OMP_CLAUSE_REDUCTION_INIT (c), NULL_TREE); TREE_SIDE_EFFECTS (OMP_CLAUSE_REDUCTION_INIT (c)) = 1; } - goto check_dup_generic; + if (TREE_CODE (t) == MEM_REF) + { + if (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (t))) == NULL_TREE + || TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (t)))) + != INTEGER_CST) + { + sorry ("variable length element type in array " + "%<reduction%> clause"); + remove = true; + break; + } + t = TREE_OPERAND (t, 0); + if (TREE_CODE (t) == ADDR_EXPR) + t = TREE_OPERAND (t, 0); + } + goto check_dup_generic_t; case OMP_CLAUSE_COPYPRIVATE: copyprivate_seen = true; @@ -12254,6 +12398,7 @@ c_finish_omp_clauses (tree clauses) check_dup_generic: t = OMP_CLAUSE_DECL (c); + check_dup_generic_t: if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) { error_at (OMP_CLAUSE_LOCATION (c), --- gcc/cp/parser.c.jj 2015-06-02 19:02:27.000000000 +0200 +++ gcc/cp/parser.c 2015-06-03 19:48:09.172144901 +0200 @@ -27839,6 +27839,7 @@ cp_parser_omp_var_list_no_open (cp_parse case OMP_CLAUSE_FROM: case OMP_CLAUSE_TO: case OMP_CLAUSE_DEPEND: + case OMP_CLAUSE_REDUCTION: while (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE)) { tree low_bound = NULL_TREE, length = NULL_TREE; --- gcc/cp/semantics.c.jj 2015-06-03 10:21:14.000000000 +0200 +++ gcc/cp/semantics.c 2015-06-10 16:09:56.462993941 +0200 @@ -4276,6 +4276,91 @@ cxx_omp_create_clause_info (tree c, tree return errorcount != save_errorcount; } +/* If DECL is DECL_OMP_PRIVATIZED_MEMBER, return corresponding + FIELD_DECL, otherwise return DECL itself. */ + +static tree +omp_clause_decl_field (tree decl) +{ + if (VAR_P (decl) + && DECL_HAS_VALUE_EXPR_P (decl) + && DECL_ARTIFICIAL (decl) + && DECL_LANG_SPECIFIC (decl) + && DECL_OMP_PRIVATIZED_MEMBER (decl)) + { + tree f = DECL_VALUE_EXPR (decl); + if (TREE_CODE (f) == INDIRECT_REF) + f = TREE_OPERAND (f, 0); + if (TREE_CODE (f) == COMPONENT_REF) + { + f = TREE_OPERAND (f, 1); + gcc_assert (TREE_CODE (f) == FIELD_DECL); + return f; + } + } + return NULL_TREE; +} + +/* Adjust DECL if needed for printing using %qE. */ + +static tree +omp_clause_printable_decl (tree decl) +{ + tree t = omp_clause_decl_field (decl); + if (t) + return t; + return decl; +} + +/* For a FIELD_DECL F and corresponding DECL_OMP_PRIVATIZED_MEMBER + VAR_DECL T that doesn't need a DECL_EXPR added, record it for + privatization. */ + +static void +omp_note_field_privatization (tree f, tree t) +{ + if (!omp_private_member_map) + omp_private_member_map = new hash_map<tree, tree>; + tree &v = omp_private_member_map->get_or_insert (f); + if (v == NULL_TREE) + { + v = t; + omp_private_member_vec.safe_push (f); + /* Signal that we don't want to create DECL_EXPR for this dummy var. */ + omp_private_member_vec.safe_push (integer_zero_node); + } +} + +/* Privatize FIELD_DECL T, return corresponding DECL_OMP_PRIVATIZED_MEMBER + dummy VAR_DECL. */ + +static tree +omp_privatize_field (tree t) +{ + tree m = finish_non_static_data_member (t, NULL_TREE, NULL_TREE); + if (m == error_mark_node) + return error_mark_node; + if (!omp_private_member_map) + omp_private_member_map = new hash_map<tree, tree>; + if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE) + { + gcc_assert (TREE_CODE (m) == INDIRECT_REF); + m = TREE_OPERAND (m, 0); + } + tree &v = omp_private_member_map->get_or_insert (t); + if (v == NULL_TREE) + { + v = create_temporary_var (TREE_TYPE (m)); + if (!DECL_LANG_SPECIFIC (v)) + retrofit_lang_decl (v); + DECL_OMP_PRIVATIZED_MEMBER (v) = 1; + SET_DECL_VALUE_EXPR (v, m); + DECL_HAS_VALUE_EXPR_P (v) = 1; + omp_private_member_vec.safe_push (t); + } + return v; +} + /* Helper function for handle_omp_array_sections. Called recursively to handle multiple array-section-subscripts. C is the clause, T current expression (initially OMP_CLAUSE_DECL), which is either @@ -4290,7 +4375,7 @@ cxx_omp_create_clause_info (tree c, tree map(a[:b][2:1][:c][:2][:d][e:f][2:5]) FIRST_NON_ONE will be 3, array-section-subscript [:b], [2:1] and [:c] all are or may have length of 1, array-section-subscript [:2] is the - first one knonwn not to have length 1. For array-section-subscript + first one known not to have length 1. For array-section-subscript <= FIRST_NON_ONE we diagnose non-contiguous arrays if low bound isn't 0 or length isn't the array domain max + 1, for > FIRST_NON_ONE we can if MAYBE_ZERO_LEN is false. MAYBE_ZERO_LEN will be true in the above @@ -4333,6 +4418,9 @@ handle_omp_array_sections_1 (tree c, tre return t; } + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + && TREE_CODE (TREE_CHAIN (t)) == FIELD_DECL) + TREE_CHAIN (t) = omp_privatize_field (TREE_CHAIN (t)); ret = handle_omp_array_sections_1 (c, TREE_CHAIN (t), types, maybe_zero_len, first_non_one); if (ret == error_mark_node || ret == NULL_TREE) @@ -4382,11 +4470,32 @@ handle_omp_array_sections_1 (tree c, tre if (length != NULL_TREE) { if (!integer_nonzerop (length)) - maybe_zero_len = true; + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + { + if (integer_zerop (length)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "zero length array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + } + else + maybe_zero_len = true; + } if (first_non_one == types.length () && (TREE_CODE (length) != INTEGER_CST || integer_onep (length))) first_non_one++; } + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION + && !integer_zerop (low_bound)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%<reduction%> array section has to be zero-based"); + return error_mark_node; + } if (TREE_CODE (type) == ARRAY_TYPE) { if (length == NULL_TREE @@ -4434,7 +4543,17 @@ handle_omp_array_sections_1 (tree c, tre return error_mark_node; } if (tree_int_cst_equal (size, low_bound)) - maybe_zero_len = true; + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + { + error_at (OMP_CLAUSE_LOCATION (c), + "zero length array section in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + return error_mark_node; + } + maybe_zero_len = true; + } else if (length == NULL_TREE && first_non_one == types.length () && tree_int_cst_equal @@ -4444,7 +4563,9 @@ handle_omp_array_sections_1 (tree c, tre } else if (length == NULL_TREE) { - maybe_zero_len = true; + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION) + maybe_zero_len = true; if (first_non_one == types.length ()) first_non_one++; } @@ -4478,7 +4599,9 @@ handle_omp_array_sections_1 (tree c, tre } else if (length == NULL_TREE) { - maybe_zero_len = true; + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION) + maybe_zero_len = true; if (first_non_one == types.length ()) first_non_one++; } @@ -4539,7 +4662,7 @@ handle_omp_array_sections (tree c) { bool maybe_zero_len = false; unsigned int first_non_one = 0; - auto_vec<tree> types; + auto_vec<tree, 10> types; tree first = handle_omp_array_sections_1 (c, OMP_CLAUSE_DECL (c), types, maybe_zero_len, first_non_one); if (first == error_mark_node) @@ -4643,7 +4766,9 @@ handle_omp_array_sections (tree c) { tree l; - if (i > first_non_one && length && integer_nonzerop (length)) + if (i > first_non_one + && ((length && integer_nonzerop (length)) + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)) continue; if (length) l = fold_convert (sizetype, length); @@ -4668,6 +4793,12 @@ handle_omp_array_sections (tree c) else if (size == NULL_TREE) { size = size_in_bytes (TREE_TYPE (types[i])); + tree eltype = TREE_TYPE (types[num - 1]); + while (TREE_CODE (eltype) == ARRAY_TYPE) + eltype = TREE_TYPE (eltype); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + size = size_binop (EXACT_DIV_EXPR, size, + size_in_bytes (eltype)); size = size_binop (MULT_EXPR, size, l); if (condition) size = fold_build3 (COND_EXPR, sizetype, condition, @@ -4681,6 +4812,24 @@ handle_omp_array_sections (tree c) { if (side_effects) size = build2 (COMPOUND_EXPR, sizetype, side_effects, size); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + { + size = size_binop (MINUS_EXPR, size, size_one_node); + tree index_type = build_index_type (size); + tree eltype = TREE_TYPE (first); + while (TREE_CODE (eltype) == ARRAY_TYPE) + eltype = TREE_TYPE (eltype); + tree type = build_array_type (eltype, index_type); + tree ptype = build_pointer_type (eltype); + if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE + && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (t)))) + t = convert_from_reference (t); + else if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + t = build_fold_addr_expr (t); + t = build2 (MEM_REF, type, t, build_int_cst (ptype, 0)); + OMP_CLAUSE_DECL (c) = t; + return false; + } OMP_CLAUSE_DECL (c) = first; OMP_CLAUSE_SIZE (c) = size; if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) @@ -5107,30 +5256,6 @@ find_omp_placeholder_r (tree *tp, int *, return NULL_TREE; } -/* Adjust DECL if needed for printing using %qE. */ - -static tree -omp_clause_printable_decl (tree decl) -{ - if (VAR_P (decl) - && DECL_HAS_VALUE_EXPR_P (decl) - && DECL_ARTIFICIAL (decl) - && DECL_LANG_SPECIFIC (decl) - && DECL_OMP_PRIVATIZED_MEMBER (decl)) - { - tree f = DECL_VALUE_EXPR (decl); - if (TREE_CODE (f) == INDIRECT_REF) - f = TREE_OPERAND (f, 0); - if (TREE_CODE (f) == COMPONENT_REF) - { - f = TREE_OPERAND (f, 1); - gcc_assert (TREE_CODE (f) == FIELD_DECL); - return f; - } - } - return decl; -} - /* Helper function of finish_omp_clauses. Handle OMP_CLAUSE_REDUCTION C. Return true if there is some error and the clause should be removed. */ @@ -5139,9 +5264,45 @@ finish_omp_reduction_clause (tree c, boo { tree t = OMP_CLAUSE_DECL (c); bool predefined = false; + if (TREE_CODE (t) == TREE_LIST) + { + gcc_assert (processing_template_decl); + return false; + } tree type = TREE_TYPE (t); + if (TREE_CODE (t) == MEM_REF) + type = TREE_TYPE (type); if (TREE_CODE (type) == REFERENCE_TYPE) type = TREE_TYPE (type); + if (TREE_CODE (type) == ARRAY_TYPE) + { + tree oatype = type; + gcc_assert (TREE_CODE (t) != MEM_REF); + while (TREE_CODE (type) == ARRAY_TYPE) + type = TREE_TYPE (type); + if (!processing_template_decl) + { + t = require_complete_type (t); + if (t == error_mark_node) + return true; + tree size = size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (oatype), + TYPE_SIZE_UNIT (type)); + if (integer_zerop (size)) + { + error ("%qE in %<reduction%> clause is a zero size array", + omp_clause_printable_decl (t)); + return true; + } + size = size_binop (MINUS_EXPR, size, size_one_node); + tree index_type = build_index_type (size); + tree atype = build_array_type (type, index_type); + tree ptype = build_pointer_type (type); + if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + t = build_fold_addr_expr (t); + t = build2 (MEM_REF, atype, t, build_int_cst (ptype, 0)); + OMP_CLAUSE_DECL (c) = t; + } + } if (type == error_mark_node) return true; else if (ARITHMETIC_TYPE_P (type)) @@ -5174,9 +5335,9 @@ finish_omp_reduction_clause (tree c, boo default: break; } - else if (TREE_CODE (type) == ARRAY_TYPE || TYPE_READONLY (type)) + else if (TYPE_READONLY (type)) { - error ("%qE has invalid type for %<reduction%>", + error ("%qE has const type for %<reduction%>", omp_clause_printable_decl (t)); return true; } @@ -5198,9 +5359,7 @@ finish_omp_reduction_clause (tree c, boo tree id = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c); - type = TYPE_MAIN_VARIANT (TREE_TYPE (t)); - if (TREE_CODE (type) == REFERENCE_TYPE) - type = TREE_TYPE (type); + type = TYPE_MAIN_VARIANT (type); OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = NULL_TREE; if (id == NULL_TREE) id = omp_reduction_id (OMP_CLAUSE_REDUCTION_CODE (c), @@ -5218,7 +5377,7 @@ finish_omp_reduction_clause (tree c, boo if (TREE_CODE (body) == STATEMENT_LIST) { tree_stmt_iterator tsi; - tree placeholder = NULL_TREE; + tree placeholder = NULL_TREE, decl_placeholder = NULL_TREE; int i; tree stmts[7]; tree atype = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (id))); @@ -5239,14 +5398,24 @@ finish_omp_reduction_clause (tree c, boo DECL_ARTIFICIAL (placeholder) = 1; DECL_IGNORED_P (placeholder) = 1; OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = placeholder; + if (TREE_CODE (t) == MEM_REF) + { + decl_placeholder = build_lang_decl (VAR_DECL, NULL_TREE, + type); + DECL_ARTIFICIAL (decl_placeholder) = 1; + DECL_IGNORED_P (decl_placeholder) = 1; + OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c) = decl_placeholder; + } if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[0]))) cxx_mark_addressable (placeholder); if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[1])) && TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c))) != REFERENCE_TYPE) - cxx_mark_addressable (OMP_CLAUSE_DECL (c)); + cxx_mark_addressable (decl_placeholder ? decl_placeholder + : OMP_CLAUSE_DECL (c)); tree omp_out = placeholder; - tree omp_in = convert_from_reference (OMP_CLAUSE_DECL (c)); + tree omp_in = decl_placeholder ? decl_placeholder + : convert_from_reference (OMP_CLAUSE_DECL (c)); if (need_static_cast) { tree rtype = build_reference_type (atype); @@ -5268,10 +5437,12 @@ finish_omp_reduction_clause (tree c, boo gcc_assert (TREE_CODE (stmts[3]) == DECL_EXPR && TREE_CODE (stmts[4]) == DECL_EXPR); if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[3]))) - cxx_mark_addressable (OMP_CLAUSE_DECL (c)); + cxx_mark_addressable (decl_placeholder ? decl_placeholder + : OMP_CLAUSE_DECL (c)); if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[4]))) cxx_mark_addressable (placeholder); - tree omp_priv = convert_from_reference (OMP_CLAUSE_DECL (c)); + tree omp_priv = decl_placeholder ? decl_placeholder + : convert_from_reference (OMP_CLAUSE_DECL (c)); tree omp_orig = placeholder; if (need_static_cast) { @@ -5310,7 +5481,8 @@ finish_omp_reduction_clause (tree c, boo else { tree init; - tree v = convert_from_reference (t); + tree v = decl_placeholder ? decl_placeholder + : convert_from_reference (t); if (AGGREGATE_TYPE_P (TREE_TYPE (v))) init = build_constructor (TREE_TYPE (v), NULL); else @@ -5329,6 +5501,9 @@ finish_omp_reduction_clause (tree c, boo omp_clause_printable_decl (t)); return true; } + if (TREE_CODE (OMP_CLAUSE_DECL (c)) == MEM_REF) + gcc_assert (TYPE_SIZE_UNIT (type) + && TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST); return false; } @@ -5365,6 +5540,32 @@ finish_omp_clauses (tree clauses, bool a goto check_dup_generic; case OMP_CLAUSE_REDUCTION: field_ok = allow_fields; + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) == TREE_LIST) + { + if (handle_omp_array_sections (c)) + { + remove = true; + break; + } + if (TREE_CODE (t) == TREE_LIST) + { + while (TREE_CODE (t) == TREE_LIST) + t = TREE_CHAIN (t); + } + else + { + gcc_assert (TREE_CODE (t) == MEM_REF); + t = TREE_OPERAND (t, 0); + if (TREE_CODE (t) == ADDR_EXPR + || TREE_CODE (t) == INDIRECT_REF) + t = TREE_OPERAND (t, 0); + } + tree n = omp_clause_decl_field (t); + if (n) + t = n; + goto check_dup_generic_t; + } goto check_dup_generic; case OMP_CLAUSE_COPYPRIVATE: copyprivate_seen = true; @@ -5435,7 +5636,15 @@ finish_omp_clauses (tree clauses, bool a } goto check_dup_generic; check_dup_generic: - t = OMP_CLAUSE_DECL (c); + t = omp_clause_decl_field (OMP_CLAUSE_DECL (c)); + if (t) + { + if (!remove) + omp_note_field_privatization (t, OMP_CLAUSE_DECL (c)); + } + else + t = OMP_CLAUSE_DECL (c); + check_dup_generic_t: if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL && (!field_ok || TREE_CODE (t) != FIELD_DECL)) { @@ -5461,65 +5670,22 @@ finish_omp_clauses (tree clauses, bool a if (!field_ok) break; handle_field_decl: - if (!remove && TREE_CODE (t) == FIELD_DECL) - { - tree m = finish_non_static_data_member (t, NULL_TREE, NULL_TREE); - if (m == error_mark_node) - { - remove = true; - break; - } - if (!omp_private_member_map) - omp_private_member_map = new hash_map<tree, tree>; - if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE) - { - gcc_assert (TREE_CODE (m) == INDIRECT_REF); - m = TREE_OPERAND (m, 0); - } - tree &v = omp_private_member_map->get_or_insert (t); - if (v == NULL_TREE) - { - v = create_temporary_var (TREE_TYPE (m)); - if (!DECL_LANG_SPECIFIC (v)) - retrofit_lang_decl (v); - DECL_OMP_PRIVATIZED_MEMBER (v) = 1; - SET_DECL_VALUE_EXPR (v, m); - DECL_HAS_VALUE_EXPR_P (v) = 1; - omp_private_member_vec.safe_push (t); - } - OMP_CLAUSE_DECL (c) = v; - } - else if (!remove - && VAR_P (t) - && DECL_HAS_VALUE_EXPR_P (t) - && DECL_ARTIFICIAL (t) - && DECL_LANG_SPECIFIC (t) - && DECL_OMP_PRIVATIZED_MEMBER (t)) - { - tree f = DECL_VALUE_EXPR (t); - if (TREE_CODE (f) == INDIRECT_REF) - f = TREE_OPERAND (f, 0); - if (TREE_CODE (f) == COMPONENT_REF) - { - f = TREE_OPERAND (f, 1); - gcc_assert (TREE_CODE (f) == FIELD_DECL); - if (!omp_private_member_map) - omp_private_member_map = new hash_map<tree, tree>; - tree &v = omp_private_member_map->get_or_insert (f); - if (v == NULL_TREE) - { - v = t; - omp_private_member_vec.safe_push (f); - /* Signal that we don't want to create - DECL_EXPR for this dummy var. */ - omp_private_member_vec.safe_push (integer_zero_node); - } - } + if (!remove + && TREE_CODE (t) == FIELD_DECL + && t == OMP_CLAUSE_DECL (c)) + { + OMP_CLAUSE_DECL (c) = omp_privatize_field (t); + if (OMP_CLAUSE_DECL (c) == error_mark_node) + remove = true; } break; case OMP_CLAUSE_FIRSTPRIVATE: - t = OMP_CLAUSE_DECL (c); + t = omp_clause_decl_field (OMP_CLAUSE_DECL (c)); + if (t) + omp_note_field_privatization (t, OMP_CLAUSE_DECL (c)); + else + t = OMP_CLAUSE_DECL (c); if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL && (!allow_fields || TREE_CODE (t) != FIELD_DECL)) { @@ -5542,7 +5708,11 @@ finish_omp_clauses (tree clauses, bool a goto handle_field_decl; case OMP_CLAUSE_LASTPRIVATE: - t = OMP_CLAUSE_DECL (c); + t = omp_clause_decl_field (OMP_CLAUSE_DECL (c)); + if (t) + omp_note_field_privatization (t, OMP_CLAUSE_DECL (c)); + else + t = OMP_CLAUSE_DECL (c); if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL && (!allow_fields || TREE_CODE (t) != FIELD_DECL)) { --- gcc/c-family/c-omp.c.jj 2015-05-21 11:12:09.000000000 +0200 +++ gcc/c-family/c-omp.c 2015-06-08 10:50:52.570868184 +0200 @@ -964,6 +964,8 @@ c_omp_split_clauses (location_t loc, enu = OMP_CLAUSE_REDUCTION_CODE (clauses); OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = OMP_CLAUSE_REDUCTION_PLACEHOLDER (clauses); + OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c) + = OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clauses); OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_SIMD]; cclauses[C_OMP_CLAUSE_SPLIT_SIMD] = c; } @@ -979,6 +981,8 @@ c_omp_split_clauses (location_t loc, enu = OMP_CLAUSE_REDUCTION_CODE (clauses); OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = OMP_CLAUSE_REDUCTION_PLACEHOLDER (clauses); + OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (c) + = OMP_CLAUSE_REDUCTION_DECL_PLACEHOLDER (clauses); OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] = c; s = C_OMP_CLAUSE_SPLIT_TEAMS; --- gcc/testsuite/gcc.dg/gomp/clause-1.c.jj 2015-04-24 12:31:52.000000000 +0200 +++ gcc/testsuite/gcc.dg/gomp/clause-1.c 2015-06-09 20:00:25.872225946 +0200 @@ -46,7 +46,7 @@ foo (int x) ; #pragma omp p reduction (*:s) /* { dg-error "user defined reduction not found for" } */ ; -#pragma omp p reduction (-:a) /* { dg-error "user defined reduction not found for" } */ +#pragma omp p reduction (-:a) ; d = 0; #pragma omp p reduction (*:d) --- gcc/testsuite/gcc.dg/gomp/reduction-1.c.jj 2015-06-10 15:05:19.742023709 +0200 +++ gcc/testsuite/gcc.dg/gomp/reduction-1.c 2015-06-10 15:31:46.031471679 +0200 @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +struct S {}; +void foo (void *, void *); +void bar (void *, void *); +void baz (void *); +#pragma omp declare reduction(+:struct S:foo (&omp_out, &omp_in))initializer(bar(&omp_priv, &omp_orig)) + +void +test (void) +{ + struct S b[10]; + #pragma omp parallel reduction(+:b[0:5]) /* { dg-error "zero length array section" } */ + baz (b); + #pragma omp parallel reduction(+:b[:10]) /* { dg-error "zero length array section" } */ + baz (b); + #pragma omp parallel reduction(+:b) /* { dg-error "is a zero size array" } */ + baz (b); +} --- gcc/testsuite/g++.dg/gomp/clause-3.C.jj 2015-04-24 12:31:59.000000000 +0200 +++ gcc/testsuite/g++.dg/gomp/clause-3.C 2015-06-09 20:01:12.858491167 +0200 @@ -46,7 +46,7 @@ foo (int x) ; #pragma omp p reduction (*:s) // { dg-error "user defined reduction not found for" } ; -#pragma omp p reduction (-:a) // { dg-error "has invalid type for" } +#pragma omp p reduction (-:a) ; d = 0; #pragma omp p reduction (*:d) --- gcc/testsuite/c-c++-common/gomp/depend-3.c.jj 2015-06-10 12:46:57.135106894 +0200 +++ gcc/testsuite/c-c++-common/gomp/depend-3.c 2015-06-10 13:05:02.336153398 +0200 @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +void bar (int a[10][10][10]); +void +foo (int a[10][10][10], int **b, int x) +{ + int c[10][10][10]; + #pragma omp task depend(out: a[2:4][3:0][:7]) /* { dg-error "zero length array section" } */ + bar (a); + #pragma omp task depend(inout: b[:7][0:0][:0]) /* { dg-error "zero length array section" } */ + bar (a); + #pragma omp task depend(in: c[:][:][10:]) /* { dg-error "zero length array section" } */ + bar (c); + #pragma omp task depend(out: a[2:4][3:0][:x]) /* { dg-error "zero length array section" } */ + bar (a); + #pragma omp task depend(inout: b[:x][0:0][:0]) /* { dg-error "zero length array section" } */ + bar (a); + #pragma omp task depend(in: c[:][x-2:x][10:]) /* { dg-error "zero length array section" } */ + bar (c); +} --- gcc/testsuite/c-c++-common/gomp/reduction-1.c.jj 2015-06-10 13:02:51.489198677 +0200 +++ gcc/testsuite/c-c++-common/gomp/reduction-1.c 2015-06-10 16:13:32.521650276 +0200 @@ -0,0 +1,51 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +void bar (int a[10][10][10]); +extern int f[][2]; /* { dg-error "has incomplete type" "" { target c++ } } */ +extern int g[]; /* { dg-error "has incomplete type" "" { target c++ } } */ +void +foo (int a[10][10][10], int **b, int x) +{ + int c[10][10][0]; + int d[0]; + char e[12]; + #pragma omp parallel reduction(+: a[:4][:0][:7]) /* { dg-error "zero length array section" } */ + bar (a); + #pragma omp parallel reduction(+: b[:7][0:0][:0]) /* { dg-error "zero length array section" } */ + bar (a); + #pragma omp parallel reduction(+: c[:][:][0:]) /* { dg-error "zero length array section|for unknown bound array type length expression must be specified" } */ + bar (a); + #pragma omp parallel reduction(+: a[:4][:0][:x]) /* { dg-error "zero length array section" } */ + bar (a); + #pragma omp parallel reduction(+: b[:x][0:0][:0]) /* { dg-error "zero length array section" } */ + bar (a); + #pragma omp parallel reduction(+: c[:][:x][0:]) /* { dg-error "zero length array section|for unknown bound array type length expression must be specified" } */ + bar (a); + #pragma omp parallel reduction(+: d) /* { dg-error "is a zero size array" } */ + bar (a); + #pragma omp parallel reduction(+: a[0:4]) + bar (a); + #pragma omp parallel reduction(+: a[2:4]) /* { dg-error "array section has to be zero-based" } */ + bar (a); + #pragma omp parallel reduction(+: e[2:4]) /* { dg-error "array section has to be zero-based" } */ + bar (a); + #pragma omp parallel reduction(+: a[0.5:2]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */ + bar (a); + #pragma omp parallel reduction(+: a[0:2.5]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */ + bar (a); + #pragma omp parallel reduction(+: f[:][0:2]) /* { dg-error "for unknown bound array type length expression must be specified" } */ + bar (a); + #pragma omp parallel reduction(+: a[:][0:10]) /* { dg-error "for pointer type length expression must be specified" } */ + bar (a); + #pragma omp parallel reduction(+: a[:10][0:12]) /* { dg-error "above array section size" } */ + bar (a); + #pragma omp parallel reduction(+: b[0:10][0:10]) /* { dg-error "array section is not contiguous" } */ + bar (a); + #pragma omp parallel reduction(+: a[0:2][0:9]) /* { dg-error "array section is not contiguous" } */ + bar (a); + #pragma omp parallel reduction(+: f) /* { dg-error "has an incomplete type|invalid use of array with unspecified bounds" } */ + bar (a); + #pragma omp parallel reduction(+: g) /* { dg-error "has an incomplete type|invalid use of array with unspecified bounds" } */ + bar (a); +} --- gcc/testsuite/c-c++-common/gomp/udr-1.c.jj 2015-06-10 15:04:03.806195170 +0200 +++ gcc/testsuite/c-c++-common/gomp/udr-1.c 2015-06-10 15:04:22.893900704 +0200 @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +struct S {}; +void foo (void *, void *); +void bar (void *, void *); +void baz (void *); +#pragma omp declare reduction(+:struct S:foo (&omp_out, &omp_in))initializer(bar(&omp_priv, &omp_orig)) + +void +test (void) +{ + struct S a, b[10]; + #pragma omp parallel reduction(+:a) + baz (&a); +} --- libgomp/testsuite/libgomp.c/reduction-10.c.jj 2015-06-10 16:28:26.025821993 +0200 +++ libgomp/testsuite/libgomp.c/reduction-10.c 2015-06-10 16:24:19.000000000 +0200 @@ -0,0 +1,105 @@ +struct A { int t; }; +struct B { char t; }; +struct C { unsigned long long t; }; +struct D { long t; }; +void +add (struct B *x, struct B *y) +{ + x->t += y->t; +} +void +zero (struct B *x) +{ + x->t = 0; +} +void +orit (struct C *x, struct C *y) +{ + y->t |= x->t; +} +#pragma omp declare reduction(+:struct A:omp_out.t += omp_in.t) +#pragma omp declare reduction(+:struct B:add (&omp_out, &omp_in)) initializer(zero (&omp_priv)) +#pragma omp declare reduction(*:struct A:omp_out.t *= omp_in.t) initializer(omp_priv = { 1 }) +#pragma omp declare reduction(|:struct C:orit (&omp_in, &omp_out)) +#pragma omp declare reduction(&:struct D:omp_out.t = omp_out.t & omp_in.t) initializer(omp_priv = { ~0L }) +#pragma omp declare reduction(maxb:short:omp_out = omp_in > omp_out ? omp_in : omp_out) initializer(omp_priv = -6) + +struct B z[10]; + +__attribute__((noinline, noclone)) void +foo (struct A (*x)[3][2], struct A *y, struct D w[1][2], int p1, long p2, long p3, int p4, + int p5, long p6, short p7) +{ + struct C a[p7 + 4]; + short b[p7]; + int i; + for (i = 0; i < p7 + 4; i++) + { + if (i < p7) + b[i] = -6; + a[i].t = 0; + } + #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2], z[:p3]) \ + reduction(*:y[:p4]) reduction(|:a[:p5]) \ + reduction(&:w[0:p6 - 1][:p6]) reduction(maxb:b) + for (i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1].t += i; + if ((i & 15) == 1) + y[0].t *= 3; + if ((i & 31) == 2) + y[1].t *= 7; + if ((i & 63) == 3) + y[2].t *= 17; + z[i / 32].t += (i & 3); + if (i < 4) + z[i].t += i; + a[i / 32].t |= 1ULL << (i & 30); + w[0][i & 1].t &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[2]) + b[2] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } + for (i = 0; i < 9; i++) + if (a[i].t != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + if (b[0] != 78 || b[1] != 12 || b[2] != 22 || b[3] != 84 || b[4] != 127) + __builtin_abort (); +} + +int +main () +{ + struct A a[4][3][2] = {}; + static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }}, + {{ 312, 381 }, { 295, 356 }, { 337, 335 }}, + {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }}, + {{ 0, 0 }, { 0, 0 }, { 0, 0 }}}; + struct A y[5] = { { 0 }, { 1 }, { 1 }, { 1 }, { 0 } }; + int y2[5] = { 0, 6561, 2401, 289, 0 }; + char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 }; + struct D w[1][2] = { { { ~0L }, { ~0L } } }; + foo (&a[1], y + 1, w, 1, 3L, 4L, 3, 4, 2L, 5); + int i, j, k; + for (i = 0; i < 4; i++) + for (j = 0; j < 3; j++) + for (k = 0; k < 2; k++) + if (a[i][j][k].t != a2[i][j][k]) + __builtin_abort (); + for (i = 0; i < 5; i++) + if (y[i].t != y2[i]) + __builtin_abort (); + for (i = 0; i < 10; i++) + if (z[i].t != z2[i]) + __builtin_abort (); + if (w[0][0].t != ~0x249249L || w[0][1].t != ~0x249249L) + __builtin_abort (); + return 0; +} --- libgomp/testsuite/libgomp.c/reduction-7.c.jj 2015-06-08 19:29:10.488133293 +0200 +++ libgomp/testsuite/libgomp.c/reduction-7.c 2015-06-08 19:08:59.000000000 +0200 @@ -0,0 +1,64 @@ +char z[10] = { 0 }; + +__attribute__((noinline, noclone)) void +foo (int (*x)[3][2], int *y, long w[1][2]) +{ + unsigned long long a[9] = {}; + short b[5] = {}; + int i; + #pragma omp parallel for reduction(+:x[0:2][:][0:2], z[:4]) \ + reduction(*:y[:3]) reduction(|:a[:4]) \ + reduction(&:w[0:1][:2]) reduction(max:b) + for (i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1] += i; + if ((i & 15) == 1) + y[0] *= 3; + if ((i & 31) == 2) + y[1] *= 7; + if ((i & 63) == 3) + y[2] *= 17; + z[i / 32] += (i & 3); + if (i < 4) + z[i] += i; + a[i / 32] |= 1ULL << (i & 30); + w[0][i & 1] &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[2]) + b[2] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } + for (i = 0; i < 9; i++) + if (a[i] != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + if (b[0] != 78 || b[1] != 12 || b[2] != 22 || b[3] != 84 || b[4] != 127) + __builtin_abort (); +} + +int +main () +{ + int a[4][3][2] = {}; + static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }}, + {{ 312, 381 }, { 295, 356 }, { 337, 335 }}, + {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }}, + {{ 0, 0 }, { 0, 0 }, { 0, 0 }}}; + int y[5] = { 0, 1, 1, 1, 0 }; + int y2[5] = { 0, 6561, 2401, 289, 0 }; + char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 }; + long w[1][2] = { ~0L, ~0L }; + foo (&a[1], y + 1, w); + if (__builtin_memcmp (a, a2, sizeof (a)) + || __builtin_memcmp (y, y2, sizeof (y)) + || __builtin_memcmp (z, z2, sizeof (z)) + || w[0][0] != ~0x249249L + || w[0][1] != ~0x249249L) + __builtin_abort (); + return 0; +} --- libgomp/testsuite/libgomp.c/reduction-8.c.jj 2015-06-08 20:20:39.379830477 +0200 +++ libgomp/testsuite/libgomp.c/reduction-8.c 2015-06-09 09:02:35.000000000 +0200 @@ -0,0 +1,98 @@ +struct A { int t; }; +struct B { char t; }; +struct C { unsigned long long t; }; +struct D { long t; }; +void +add (struct B *x, struct B *y) +{ + x->t += y->t; +} +void +zero (struct B *x) +{ + x->t = 0; +} +void +orit (struct C *x, struct C *y) +{ + y->t |= x->t; +} +#pragma omp declare reduction(+:struct A:omp_out.t += omp_in.t) +#pragma omp declare reduction(+:struct B:add (&omp_out, &omp_in)) initializer(zero (&omp_priv)) +#pragma omp declare reduction(*:struct A:omp_out.t *= omp_in.t) initializer(omp_priv = { 1 }) +#pragma omp declare reduction(|:struct C:orit (&omp_in, &omp_out)) +#pragma omp declare reduction(&:struct D:omp_out.t = omp_out.t & omp_in.t) initializer(omp_priv = { ~0L }) +#pragma omp declare reduction(maxb:short:omp_out = omp_in > omp_out ? omp_in : omp_out) initializer(omp_priv = -6) + +struct B z[10]; + +__attribute__((noinline, noclone)) void +foo (struct A (*x)[3][2], struct A *y, struct D w[1][2]) +{ + struct C a[9] = {}; + short b[5] = {}; + int i; + #pragma omp parallel for reduction(+:x[0:2][:][0:2], z[:4]) \ + reduction(*:y[:3]) reduction(|:a[:4]) \ + reduction(&:w[0:1][:2]) reduction(maxb:b) + for (i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1].t += i; + if ((i & 15) == 1) + y[0].t *= 3; + if ((i & 31) == 2) + y[1].t *= 7; + if ((i & 63) == 3) + y[2].t *= 17; + z[i / 32].t += (i & 3); + if (i < 4) + z[i].t += i; + a[i / 32].t |= 1ULL << (i & 30); + w[0][i & 1].t &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[2]) + b[2] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } + for (i = 0; i < 9; i++) + if (a[i].t != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + if (b[0] != 78 || b[1] != 12 || b[2] != 22 || b[3] != 84 || b[4] != 127) + __builtin_abort (); +} + +int +main () +{ + struct A a[4][3][2] = {}; + static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }}, + {{ 312, 381 }, { 295, 356 }, { 337, 335 }}, + {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }}, + {{ 0, 0 }, { 0, 0 }, { 0, 0 }}}; + struct A y[5] = { { 0 }, { 1 }, { 1 }, { 1 }, { 0 } }; + int y2[5] = { 0, 6561, 2401, 289, 0 }; + char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 }; + struct D w[1][2] = { { { ~0L }, { ~0L } } }; + foo (&a[1], y + 1, w); + int i, j, k; + for (i = 0; i < 4; i++) + for (j = 0; j < 3; j++) + for (k = 0; k < 2; k++) + if (a[i][j][k].t != a2[i][j][k]) + __builtin_abort (); + for (i = 0; i < 5; i++) + if (y[i].t != y2[i]) + __builtin_abort (); + for (i = 0; i < 10; i++) + if (z[i].t != z2[i]) + __builtin_abort (); + if (w[0][0].t != ~0x249249L || w[0][1].t != ~0x249249L) + __builtin_abort (); + return 0; +} --- libgomp/testsuite/libgomp.c/reduction-9.c.jj 2015-06-09 19:58:53.161675767 +0200 +++ libgomp/testsuite/libgomp.c/reduction-9.c 2015-06-09 16:52:21.000000000 +0200 @@ -0,0 +1,71 @@ +char z[10] = { 0 }; + +__attribute__((noinline, noclone)) void +foo (int (*x)[3][2], int *y, long w[1][2], int p1, long p2, long p3, int p4, + int p5, long p6, short p7) +{ + unsigned long long a[p7 + 4]; + short b[p7]; + int i; + for (i = 0; i < p7 + 4; i++) + { + if (i < p7) + b[i] = -6; + a[i] = 0; + } + #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2], z[:p3]) \ + reduction(*:y[:p4]) reduction(|:a[:p5]) \ + reduction(&:w[0:p6 - 1][:p6]) reduction(max:b) + for (i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1] += i; + if ((i & 15) == 1) + y[0] *= 3; + if ((i & 31) == 2) + y[1] *= 7; + if ((i & 63) == 3) + y[2] *= 17; + z[i / 32] += (i & 3); + if (i < 4) + z[i] += i; + a[i / 32] |= 1ULL << (i & 30); + w[0][i & 1] &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[2]) + b[2] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } + for (i = 0; i < 9; i++) + if (a[i] != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + if (b[0] != 78 || b[1] != 12 || b[2] != 22 || b[3] != 84 || b[4] != 127) + __builtin_abort (); +} + +int +main () +{ + int a[4][3][2] = {}; + static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }}, + {{ 312, 381 }, { 295, 356 }, { 337, 335 }}, + {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }}, + {{ 0, 0 }, { 0, 0 }, { 0, 0 }}}; + int y[5] = { 0, 1, 1, 1, 0 }; + int y2[5] = { 0, 6561, 2401, 289, 0 }; + char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 }; + long w[1][2] = { ~0L, ~0L }; + foo (&a[1], y + 1, w, 1, 3L, 4L, 3, 4, 2L, 5); + if (__builtin_memcmp (a, a2, sizeof (a)) + || __builtin_memcmp (y, y2, sizeof (y)) + || __builtin_memcmp (z, z2, sizeof (z)) + || w[0][0] != ~0x249249L + || w[0][1] != ~0x249249L) + __builtin_abort (); + return 0; +} --- libgomp/testsuite/libgomp.c++/taskloop-5.C.jj 2015-06-02 11:32:01.000000000 +0200 +++ libgomp/testsuite/libgomp.c++/taskloop-5.C 2015-06-08 17:18:27.833303433 +0200 @@ -4,6 +4,7 @@ __attribute__((noinline, noclone)) void foo (int &b) { #pragma omp parallel +#pragma omp single { bool f = false; #pragma omp taskloop firstprivate (b, f) @@ -23,6 +24,7 @@ foo (int &b) } int n; #pragma omp parallel +#pragma omp single { bool f = false; #pragma omp taskloop firstprivate (f) lastprivate (b, n) @@ -40,6 +42,7 @@ foo (int &b) __builtin_abort (); b = 9; #pragma omp parallel +#pragma omp single { bool f = false; #pragma omp taskloop firstprivate (b, f) lastprivate (b, n) --- libgomp/testsuite/libgomp.c++/reduction-5.C.jj 2015-06-05 21:30:00.958847239 +0200 +++ libgomp/testsuite/libgomp.c++/reduction-5.C 2015-06-08 17:50:15.000000000 +0200 @@ -0,0 +1,127 @@ +char z[10] = { 0 }; + +__attribute__((noinline, noclone)) void +foo (int (*&x)[3][2], int *y, long (&w)[1][2]) +{ + unsigned long long a[9] = {}; + short b[5] = {}; + #pragma omp parallel for reduction(+:x[0:2][:][0:2], z[:4]) \ + reduction(*:y[:3]) reduction(|:a[:4]) \ + reduction(&:w[0:][:2]) reduction(max:b) + for (int i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1] += i; + if ((i & 15) == 1) + y[0] *= 3; + if ((i & 31) == 2) + y[1] *= 7; + if ((i & 63) == 3) + y[2] *= 17; + z[i / 32] += (i & 3); + if (i < 4) + z[i] += i; + a[i / 32] |= 1ULL << (i & 30); + w[0][i & 1] &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[2]) + b[2] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } + for (int i = 0; i < 9; i++) + if (a[i] != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + if (b[0] != 78 || b[1] != 12 || b[2] != 22 || b[3] != 84 || b[4] != 127) + __builtin_abort (); +} + +int a3[4][3][2]; +int (*p3)[3][2] = &a3[1]; +int y3[5] = { 0, 1, 1, 1, 0 }; +long w3[1][2] = { ~0L, ~0L }; +short bb[5]; + +struct S +{ + int (*&x)[3][2]; + int *y; + long (&w)[1][2]; + char z[10]; + short (&b)[5]; + unsigned long long a[9]; + S() : x(p3), y(y3+1), w(w3), z(), a(), b(bb) {} + __attribute__((noinline, noclone)) void foo (); +}; + +void +S::foo () +{ + #pragma omp parallel for reduction(+:x[0:2][:][0:2], z[:4]) \ + reduction(*:y[:3]) reduction(|:a[:4]) \ + reduction(&:w[0:][:2]) reduction(max:b) + for (int i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1] += i; + if ((i & 15) == 1) + y[0] *= 3; + if ((i & 31) == 2) + y[1] *= 7; + if ((i & 63) == 3) + y[2] *= 17; + z[i / 32] += (i & 3); + if (i < 4) + z[i] += i; + a[i / 32] |= 1ULL << (i & 30); + w[0][i & 1] &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[2]) + b[2] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } +} + +int +main () +{ + int a[4][3][2] = {}; + static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }}, + {{ 312, 381 }, { 295, 356 }, { 337, 335 }}, + {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }}, + {{ 0, 0 }, { 0, 0 }, { 0, 0 }}}; + int (*p)[3][2] = &a[1]; + int y[5] = { 0, 1, 1, 1, 0 }; + int y2[5] = { 0, 6561, 2401, 289, 0 }; + char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 }; + long w[1][2] = { ~0L, ~0L }; + foo (p, y + 1, w); + if (__builtin_memcmp (a, a2, sizeof (a)) + || __builtin_memcmp (y, y2, sizeof (y)) + || __builtin_memcmp (z, z2, sizeof (z)) + || w[0][0] != ~0x249249L + || w[0][1] != ~0x249249L) + __builtin_abort (); + S s; + s.foo (); + for (int i = 0; i < 9; i++) + if (s.a[i] != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + if (__builtin_memcmp (a3, a2, sizeof (a3)) + || __builtin_memcmp (y3, y2, sizeof (y3)) + || __builtin_memcmp (s.z, z2, sizeof (s.z)) + || w3[0][0] != ~0x249249L + || w3[0][1] != ~0x249249L) + __builtin_abort (); + if (bb[0] != 78 || bb[1] != 12 || bb[2] != 22 || bb[3] != 84 || bb[4] != 127) + __builtin_abort (); +} --- libgomp/testsuite/libgomp.c++/reduction-6.C.jj 2015-06-08 16:07:14.557996117 +0200 +++ libgomp/testsuite/libgomp.c++/reduction-6.C 2015-06-10 18:15:23.000000000 +0200 @@ -0,0 +1,195 @@ +template <typename T> +struct A +{ + A () { t = 0; } + A (T x) { t = x; } + A (const A &x) { t = x.t; } + ~A () {} + T t; +}; +template <typename T> +struct M +{ + M () { t = 1; } + M (T x) { t = x; } + M (const M &x) { t = x.t; } + ~M () {} + T t; +}; +template <typename T> +struct B +{ + B () { t = ~(T) 0; } + B (T x) { t = x; } + B (const B &x) { t = x.t; } + ~B () {} + T t; +}; +template <typename T> +void +add (T &x, T &y) +{ + x.t += y.t; +} +template <typename T> +void +zero (T &x) +{ + x.t = 0; +} +template <typename T> +void +orit (T *x, T *y) +{ + y->t |= x->t; +} +B<long> bb; +#pragma omp declare reduction(+:A<int>:omp_out.t += omp_in.t) +#pragma omp declare reduction(+:A<char>:add (omp_out, omp_in)) initializer(zero (omp_priv)) +#pragma omp declare reduction(*:M<int>:omp_out.t *= omp_in.t) initializer(omp_priv = 1) +#pragma omp declare reduction(|:A<unsigned long long>:orit (&omp_in, &omp_out)) +#pragma omp declare reduction(&:B<long>:omp_out.t = omp_out.t & omp_in.t) initializer(orit (&omp_priv, &omp_orig)) +#pragma omp declare reduction(maxb:short:omp_out = omp_in > omp_out ? omp_in : omp_out) initializer(omp_priv = -6) + +A<char> z[10]; + +__attribute__((noinline, noclone)) void +foo (A<int> (*&x)[3][2], M<int> *y, B<long> (&w)[1][2]) +{ + A<unsigned long long> a[9]; + short bb[5] = {}; + short (&b)[5] = bb; + #pragma omp parallel for reduction(+:x[0:2][:][0:2], z[:4]) \ + reduction(*:y[:3]) reduction(|:a[:4]) \ + reduction(&:w[0:][:2]) reduction(maxb:b) + for (int i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1].t += i; + if ((i & 15) == 1) + y[0].t *= 3; + if ((i & 31) == 2) + y[1].t *= 7; + if ((i & 63) == 3) + y[2].t *= 17; + z[i / 32].t += (i & 3); + if (i < 4) + z[i].t += i; + a[i / 32].t |= 1ULL << (i & 30); + w[0][i & 1].t &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[2]) + b[2] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } + for (int i = 0; i < 9; i++) + if (a[i].t != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + if (bb[0] != 78 || bb[1] != 12 || bb[2] != 22 || bb[3] != 84 || bb[4] != 127) + __builtin_abort (); +} + +A<int> a3[4][3][2]; +A<int> (*p3)[3][2] = &a3[1]; +M<int> y3[5] = { 0, 1, 1, 1, 0 }; +B<long> w3[1][2]; + +struct S +{ + A<int> (*&x)[3][2]; + M<int> *y; + B<long> (&w)[1][2]; + A<char> z[10]; + short b[5]; + A<unsigned long long> a[9]; + S() : x(p3), y(y3+1), w(w3), z(), a(), b() {} + __attribute__((noinline, noclone)) void foo (); +}; + +void +S::foo () +{ + #pragma omp parallel for reduction(+:x[0:2][:][0:2], z[:4]) \ + reduction(*:y[:3]) reduction(|:a[:4]) \ + reduction(&:w[0:][:2]) reduction(maxb:b) + for (int i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1].t += i; + if ((i & 15) == 1) + y[0].t *= 3; + if ((i & 31) == 2) + y[1].t *= 7; + if ((i & 63) == 3) + y[2].t *= 17; + z[i / 32].t += (i & 3); + if (i < 4) + z[i].t += i; + a[i / 32].t |= 1ULL << (i & 30); + w[0][i & 1].t &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[2]) + b[2] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } +} + +int +main () +{ + A<int> a[4][3][2]; + static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }}, + {{ 312, 381 }, { 295, 356 }, { 337, 335 }}, + {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }}, + {{ 0, 0 }, { 0, 0 }, { 0, 0 }}}; + A<int> (*p)[3][2] = &a[1]; + M<int> y[5] = { 0, 1, 1, 1, 0 }; + int y2[5] = { 0, 6561, 2401, 289, 0 }; + char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 }; + B<long> w[1][2]; + foo (p, y + 1, w); + for (int i = 0; i < 4; i++) + for (int j = 0; j < 3; j++) + for (int k = 0; k < 2; k++) + if (a[i][j][k].t != a2[i][j][k]) + __builtin_abort (); + for (int i = 0; i < 5; i++) + if (y[i].t != y2[i]) + __builtin_abort (); + for (int i = 0; i < 10; i++) + if (z[i].t != z2[i]) + __builtin_abort (); + if (w[0][0].t != ~0x249249L || w[0][1].t != ~0x249249L) + __builtin_abort (); + S s; + s.foo (); + for (int i = 0; i < 9; i++) + if (s.a[i].t != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + for (int i = 0; i < 4; i++) + for (int j = 0; j < 3; j++) + for (int k = 0; k < 2; k++) + if (a3[i][j][k].t != a2[i][j][k]) + __builtin_abort (); + for (int i = 0; i < 5; i++) + if (y3[i].t != y2[i]) + __builtin_abort (); + for (int i = 0; i < 10; i++) + if (s.z[i].t != z2[i]) + __builtin_abort (); + if (w3[0][0].t != ~0x249249L || w3[0][1].t != ~0x249249L) + __builtin_abort (); + if (s.b[0] != 78 || s.b[1] != 12 || s.b[2] != 22 + || s.b[3] != 84 || s.b[4] != 127) + __builtin_abort (); +} --- libgomp/testsuite/libgomp.c++/reduction-7.C.jj 2015-06-10 17:08:23.089694851 +0200 +++ libgomp/testsuite/libgomp.c++/reduction-7.C 2015-06-10 17:08:07.000000000 +0200 @@ -0,0 +1,134 @@ +char z[10] = { 0 }; + +__attribute__((noinline, noclone)) void +foo (int (*&x)[3][2], int *y, long (&w)[1][2], int p1, long p2, long p3, int p4, + int p5, long p6, short p7) +{ + unsigned long long a[p7 + 4]; + short b[p7]; + for (int i = 0; i < p7 + 4; i++) + { + if (i < p7) + b[i] = -6; + a[i] = 0; + } + #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2], z[:p3]) \ + reduction(*:y[:p4]) reduction(|:a[:p5]) \ + reduction(&:w[0:p6 - 1][:p6]) reduction(max:b) + for (int i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1] += i; + if ((i & 15) == 1) + y[0] *= 3; + if ((i & 31) == 2) + y[1] *= 7; + if ((i & 63) == 3) + y[2] *= 17; + z[i / 32] += (i & 3); + if (i < 4) + z[i] += i; + a[i / 32] |= 1ULL << (i & 30); + w[0][i & 1] &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[2]) + b[2] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } + for (int i = 0; i < 9; i++) + if (a[i] != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + if (b[0] != 78 || b[1] != 12 || b[2] != 22 || b[3] != 84 || b[4] != 127) + __builtin_abort (); +} + +int a3[4][3][2]; +int (*p3)[3][2] = &a3[1]; +int y3[5] = { 0, 1, 1, 1, 0 }; +long w3[1][2] = { ~0L, ~0L }; +short bb[5]; + +struct S +{ + int (*&x)[3][2]; + int *y; + long (&w)[1][2]; + char z[10]; + short (&b)[5]; + unsigned long long a[9]; + S() : x(p3), y(y3+1), w(w3), z(), a(), b(bb) {} + __attribute__((noinline, noclone)) void foo (int, long, long, int, int, long, short); +}; + +void +S::foo (int p1, long p2, long p3, int p4, int p5, long p6, short p7) +{ + #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2], z[:p3]) \ + reduction(*:y[:p4]) reduction(|:a[:p5]) \ + reduction(&:w[0:p6 - 1][:p6]) reduction(max:b[0:p7]) + for (int i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1] += i; + if ((i & 15) == 1) + y[0] *= 3; + if ((i & 31) == 2) + y[1] *= 7; + if ((i & 63) == 3) + y[2] *= 17; + z[i / 32] += (i & 3); + if (i < 4) + z[i] += i; + a[i / 32] |= 1ULL << (i & 30); + w[0][i & 1] &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[2]) + b[2] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } +} + +int +main () +{ + int a[4][3][2] = {}; + static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }}, + {{ 312, 381 }, { 295, 356 }, { 337, 335 }}, + {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }}, + {{ 0, 0 }, { 0, 0 }, { 0, 0 }}}; + int (*p)[3][2] = &a[1]; + int y[5] = { 0, 1, 1, 1, 0 }; + int y2[5] = { 0, 6561, 2401, 289, 0 }; + char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 }; + long w[1][2] = { ~0L, ~0L }; + foo (p, y + 1, w, 1, 3L, 4L, 3, 4, 2L, 5); + if (__builtin_memcmp (a, a2, sizeof (a)) + || __builtin_memcmp (y, y2, sizeof (y)) + || __builtin_memcmp (z, z2, sizeof (z)) + || w[0][0] != ~0x249249L + || w[0][1] != ~0x249249L) + __builtin_abort (); + S s; + s.foo (1, 3L, 4L, 3, 4, 2L, 5); + for (int i = 0; i < 9; i++) + if (s.a[i] != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + if (__builtin_memcmp (a3, a2, sizeof (a3)) + || __builtin_memcmp (y3, y2, sizeof (y3)) + || __builtin_memcmp (s.z, z2, sizeof (s.z)) + || w3[0][0] != ~0x249249L + || w3[0][1] != ~0x249249L) + __builtin_abort (); + if (bb[0] != 78 || bb[1] != 12 || bb[2] != 22 || bb[3] != 84 || bb[4] != 127) + __builtin_abort (); +} --- libgomp/testsuite/libgomp.c++/reduction-8.C.jj 2015-06-10 18:15:51.897241899 +0200 +++ libgomp/testsuite/libgomp.c++/reduction-8.C 2015-06-10 18:14:26.000000000 +0200 @@ -0,0 +1,198 @@ +template <typename T> +struct A +{ + A () { t = 0; } + A (T x) { t = x; } + A (const A &x) { t = x.t; } + ~A () {} + T t; +}; +template <typename T> +struct M +{ + M () { t = 1; } + M (T x) { t = x; } + M (const M &x) { t = x.t; } + ~M () {} + T t; +}; +template <typename T> +struct B +{ + B () { t = ~(T) 0; } + B (T x) { t = x; } + B (const B &x) { t = x.t; } + ~B () {} + T t; +}; +template <typename T> +void +add (T &x, T &y) +{ + x.t += y.t; +} +template <typename T> +void +zero (T &x) +{ + x.t = 0; +} +template <typename T> +void +orit (T *x, T *y) +{ + y->t |= x->t; +} +B<long> bb; +#pragma omp declare reduction(+:A<int>:omp_out.t += omp_in.t) +#pragma omp declare reduction(+:A<char>:add (omp_out, omp_in)) initializer(zero (omp_priv)) +#pragma omp declare reduction(*:M<int>:omp_out.t *= omp_in.t) initializer(omp_priv = 1) +#pragma omp declare reduction(|:A<unsigned long long>:orit (&omp_in, &omp_out)) +#pragma omp declare reduction(&:B<long>:omp_out.t = omp_out.t & omp_in.t) initializer(orit (&omp_priv, &omp_orig)) +#pragma omp declare reduction(maxb:short:omp_out = omp_in > omp_out ? omp_in : omp_out) initializer(omp_priv = -6) + +A<char> z[10]; + +__attribute__((noinline, noclone)) void +foo (A<int> (*&x)[3][2], M<int> *y, B<long> (&w)[1][2], int p1, long p2, long p3, int p4, + int p5, long p6, short p7) +{ + A<unsigned long long> a[p7 + 4]; + short bb[p7]; + short (&b)[p7] = bb; + for (int i = 0; i < p7; i++) + bb[i] = -6; + #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2], z[:p3]) \ + reduction(*:y[:p4]) reduction(|:a[:p5]) \ + reduction(&:w[0:p6 - 1][:p6]) reduction(maxb:b) + for (int i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1].t += i; + if ((i & 15) == 1) + y[0].t *= 3; + if ((i & 31) == 2) + y[1].t *= 7; + if ((i & 63) == 3) + y[2].t *= 17; + z[i / 32].t += (i & 3); + if (i < 4) + z[i].t += i; + a[i / 32].t |= 1ULL << (i & 30); + w[0][i & 1].t &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[2]) + b[2] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } + for (int i = 0; i < 9; i++) + if (a[i].t != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + if (bb[0] != 78 || bb[1] != 12 || bb[2] != 22 || bb[3] != 84 || bb[4] != 127) + __builtin_abort (); +} + +A<int> a3[4][3][2]; +A<int> (*p3)[3][2] = &a3[1]; +M<int> y3[5] = { 0, 1, 1, 1, 0 }; +B<long> w3[1][2]; + +struct S +{ + A<int> (*&x)[3][2]; + M<int> *y; + B<long> (&w)[1][2]; + A<char> z[10]; + short b[5]; + A<unsigned long long> a[9]; + S() : x(p3), y(y3+1), w(w3), z(), a(), b() {} + __attribute__((noinline, noclone)) void foo (int, long, long, int, int, long, short); +}; + +void +S::foo (int p1, long p2, long p3, int p4, int p5, long p6, short p7) +{ + #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2][0:2], z[:p3]) \ + reduction(*:y[:p4]) reduction(|:a[:p5]) \ + reduction(&:w[0:p6 - 1][:p6]) reduction(maxb:b) + for (int i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1].t += i; + if ((i & 15) == 1) + y[0].t *= 3; + if ((i & 31) == 2) + y[1].t *= 7; + if ((i & 63) == 3) + y[2].t *= 17; + z[i / 32].t += (i & 3); + if (i < 4) + z[i].t += i; + a[i / 32].t |= 1ULL << (i & 30); + w[0][i & 1].t &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[2]) + b[2] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } +} + +int +main () +{ + A<int> a[4][3][2]; + static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }}, + {{ 312, 381 }, { 295, 356 }, { 337, 335 }}, + {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }}, + {{ 0, 0 }, { 0, 0 }, { 0, 0 }}}; + A<int> (*p)[3][2] = &a[1]; + M<int> y[5] = { 0, 1, 1, 1, 0 }; + int y2[5] = { 0, 6561, 2401, 289, 0 }; + char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 }; + B<long> w[1][2]; + foo (p, y + 1, w, 1, 3L, 4L, 3, 4, 2L, 5); + for (int i = 0; i < 4; i++) + for (int j = 0; j < 3; j++) + for (int k = 0; k < 2; k++) + if (a[i][j][k].t != a2[i][j][k]) + __builtin_abort (); + for (int i = 0; i < 5; i++) + if (y[i].t != y2[i]) + __builtin_abort (); + for (int i = 0; i < 10; i++) + if (z[i].t != z2[i]) + __builtin_abort (); + if (w[0][0].t != ~0x249249L || w[0][1].t != ~0x249249L) + __builtin_abort (); + S s; + s.foo (1, 3L, 4L, 3, 4, 2L, 5); + for (int i = 0; i < 9; i++) + if (s.a[i].t != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + for (int i = 0; i < 4; i++) + for (int j = 0; j < 3; j++) + for (int k = 0; k < 2; k++) + if (a3[i][j][k].t != a2[i][j][k]) + __builtin_abort (); + for (int i = 0; i < 5; i++) + if (y3[i].t != y2[i]) + __builtin_abort (); + for (int i = 0; i < 10; i++) + if (s.z[i].t != z2[i]) + __builtin_abort (); + if (w3[0][0].t != ~0x249249L || w3[0][1].t != ~0x249249L) + __builtin_abort (); + if (s.b[0] != 78 || s.b[1] != 12 || s.b[2] != 22 + || s.b[3] != 84 || s.b[4] != 127) + __builtin_abort (); +} --- libgomp/testsuite/libgomp.c++/reduction-9.C.jj 2015-06-10 19:02:56.760724297 +0200 +++ libgomp/testsuite/libgomp.c++/reduction-9.C 2015-06-10 19:02:23.000000000 +0200 @@ -0,0 +1,130 @@ +char z[10] = { 0 }; + +template <int N> +__attribute__((noinline, noclone)) void +foo (int (*&x)[3][N], int *y, long (&w)[1][N]) +{ + unsigned long long a[9] = {}; + short b[5] = {}; + #pragma omp parallel for reduction(+:x[0:N][:][0:N], z[:4]) \ + reduction(*:y[:3]) reduction(|:a[:4]) \ + reduction(&:w[0:][:N]) reduction(max:b) + for (int i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1] += i; + if ((i & 15) == 1) + y[0] *= 3; + if ((i & 31) == N) + y[1] *= 7; + if ((i & 63) == 3) + y[N] *= 17; + z[i / 32] += (i & 3); + if (i < 4) + z[i] += i; + a[i / 32] |= 1ULL << (i & 30); + w[0][i & 1] &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[N]) + b[N] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } + for (int i = 0; i < 9; i++) + if (a[i] != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + if (b[0] != 78 || b[1] != 12 || b[N] != 22 || b[3] != 84 || b[4] != 127) + __builtin_abort (); +} + +int a3[4][3][2]; +int (*p3)[3][2] = &a3[1]; +int y3[5] = { 0, 1, 1, 1, 0 }; +long w3[1][2] = { ~0L, ~0L }; +short bb[5]; + +template <int N> +struct S +{ + int (*&x)[3][N]; + int *y; + long (&w)[1][N]; + char z[10]; + short (&b)[5]; + unsigned long long a[9]; + S() : x(p3), y(y3+1), w(w3), z(), a(), b(bb) {} + __attribute__((noinline, noclone)) void foo (); +}; + +template <int N> +void +S<N>::foo () +{ + #pragma omp parallel for reduction(+:x[0:N][:][0:N], z[:4]) \ + reduction(*:y[:3]) reduction(|:a[:4]) \ + reduction(&:w[0:][:N]) reduction(max:b) + for (int i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1] += i; + if ((i & 15) == 1) + y[0] *= 3; + if ((i & 31) == N) + y[1] *= 7; + if ((i & 63) == 3) + y[N] *= 17; + z[i / 32] += (i & 3); + if (i < 4) + z[i] += i; + a[i / 32] |= 1ULL << (i & 30); + w[0][i & 1] &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[N]) + b[N] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } +} + +int +main () +{ + int a[4][3][2] = {}; + static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }}, + {{ 312, 381 }, { 295, 356 }, { 337, 335 }}, + {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }}, + {{ 0, 0 }, { 0, 0 }, { 0, 0 }}}; + int (*p)[3][2] = &a[1]; + int y[5] = { 0, 1, 1, 1, 0 }; + int y2[5] = { 0, 6561, 2401, 289, 0 }; + char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 }; + long w[1][2] = { ~0L, ~0L }; + foo<2> (p, y + 1, w); + if (__builtin_memcmp (a, a2, sizeof (a)) + || __builtin_memcmp (y, y2, sizeof (y)) + || __builtin_memcmp (z, z2, sizeof (z)) + || w[0][0] != ~0x249249L + || w[0][1] != ~0x249249L) + __builtin_abort (); + S<2> s; + s.foo (); + for (int i = 0; i < 9; i++) + if (s.a[i] != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + if (__builtin_memcmp (a3, a2, sizeof (a3)) + || __builtin_memcmp (y3, y2, sizeof (y3)) + || __builtin_memcmp (s.z, z2, sizeof (s.z)) + || w3[0][0] != ~0x249249L + || w3[0][1] != ~0x249249L) + __builtin_abort (); + if (bb[0] != 78 || bb[1] != 12 || bb[2] != 22 || bb[3] != 84 || bb[4] != 127) + __builtin_abort (); +} --- libgomp/testsuite/libgomp.c++/reduction-10.C.jj 2015-06-10 19:05:53.932997634 +0200 +++ libgomp/testsuite/libgomp.c++/reduction-10.C 2015-06-10 19:05:19.000000000 +0200 @@ -0,0 +1,201 @@ +template <typename T> +struct A +{ + A () { t = 0; } + A (T x) { t = x; } + A (const A &x) { t = x.t; } + ~A () {} + T t; +}; +template <typename T> +struct M +{ + M () { t = 1; } + M (T x) { t = x; } + M (const M &x) { t = x.t; } + ~M () {} + T t; +}; +template <typename T> +struct B +{ + B () { t = ~(T) 0; } + B (T x) { t = x; } + B (const B &x) { t = x.t; } + ~B () {} + T t; +}; +template <typename T> +void +add (T &x, T &y) +{ + x.t += y.t; +} +template <typename T> +void +zero (T &x) +{ + x.t = 0; +} +template <typename T> +void +orit (T *x, T *y) +{ + y->t |= x->t; +} +B<long> bb; +#pragma omp declare reduction(+:A<int>:omp_out.t += omp_in.t) +#pragma omp declare reduction(+:A<char>:add (omp_out, omp_in)) initializer(zero (omp_priv)) +#pragma omp declare reduction(*:M<int>:omp_out.t *= omp_in.t) initializer(omp_priv = 1) +#pragma omp declare reduction(|:A<unsigned long long>:orit (&omp_in, &omp_out)) +#pragma omp declare reduction(&:B<long>:omp_out.t = omp_out.t & omp_in.t) initializer(orit (&omp_priv, &omp_orig)) +#pragma omp declare reduction(maxb:short:omp_out = omp_in > omp_out ? omp_in : omp_out) initializer(omp_priv = -6) + +A<char> z[10]; + +template <int N> +__attribute__((noinline, noclone)) void +foo (A<int> (*&x)[3][N], M<int> *y, B<long> (&w)[1][N], int p1, long p2, long p3, int p4, + int p5, long p6, short p7) +{ + A<unsigned long long> a[p7 + 4]; + short bb[p7]; + short (&b)[p7] = bb; + for (int i = 0; i < p7; i++) + bb[i] = -6; + #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2 + N - 2], z[:p3]) \ + reduction(*:y[:p4]) reduction(|:a[:p5 - N + 2]) \ + reduction(&:w[0:p6 - 3 + N][:p6]) reduction(maxb:b) + for (int i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1].t += i; + if ((i & 15) == 1) + y[0].t *= 3; + if ((i & 31) == N) + y[1].t *= 7; + if ((i & 63) == 3) + y[N].t *= 17; + z[i / 32].t += (i & 3); + if (i < 4) + z[i].t += i; + a[i / 32].t |= 1ULL << (i & 30); + w[0][i & 1].t &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[N]) + b[N] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } + for (int i = 0; i < 9; i++) + if (a[i].t != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + if (bb[0] != 78 || bb[1] != 12 || bb[N] != 22 || bb[3] != 84 || bb[4] != 127) + __builtin_abort (); +} + +A<int> a3[4][3][2]; +A<int> (*p3)[3][2] = &a3[1]; +M<int> y3[5] = { 0, 1, 1, 1, 0 }; +B<long> w3[1][2]; + +template <int N> +struct S +{ + A<int> (*&x)[3][N]; + M<int> *y; + B<long> (&w)[1][N]; + A<char> z[10]; + short b[5]; + A<unsigned long long> a[9]; + S() : x(p3), y(y3+1), w(w3), z(), a(), b() {} + __attribute__((noinline, noclone)) void foo (int, long, long, int, int, long, short); +}; + +template <int N> +void +S<N>::foo (int p1, long p2, long p3, int p4, int p5, long p6, short p7) +{ + #pragma omp parallel for reduction(+:x[0:p1 + 1][:p2][0:N], z[:p3 + N - 2]) \ + reduction(*:y[:p4]) reduction(|:a[:p5]) \ + reduction(&:w[0:p6 - 3 + N][:p6]) reduction(maxb:b) + for (int i = 0; i < 128; i++) + { + x[i / 64][i % 3][(i / 4) & 1].t += i; + if ((i & 15) == 1) + y[0].t *= 3; + if ((i & 31) == N) + y[1].t *= 7; + if ((i & 63) == 3) + y[N].t *= 17; + z[i / 32].t += (i & 3); + if (i < 4) + z[i].t += i; + a[i / 32].t |= 1ULL << (i & 30); + w[0][i & 1].t &= ~(1L << (i / 17 * 3)); + if ((i % 79) > b[0]) + b[0] = i % 79; + if ((i % 13) > b[1]) + b[1] = i % 13; + if ((i % 23) > b[N]) + b[N] = i % 23; + if ((i % 85) > b[3]) + b[3] = i % 85; + if ((i % 192) > b[4]) + b[4] = i % 192; + } +} + +int +main () +{ + A<int> a[4][3][2]; + static int a2[4][3][2] = {{{ 0, 0 }, { 0, 0 }, { 0, 0 }}, + {{ 312, 381 }, { 295, 356 }, { 337, 335 }}, + {{ 1041, 975 }, { 1016, 1085 }, { 935, 1060 }}, + {{ 0, 0 }, { 0, 0 }, { 0, 0 }}}; + A<int> (*p)[3][2] = &a[1]; + M<int> y[5] = { 0, 1, 1, 1, 0 }; + int y2[5] = { 0, 6561, 2401, 289, 0 }; + char z2[10] = { 48, 49, 50, 51, 0, 0, 0, 0, 0, 0 }; + B<long> w[1][2]; + foo<2> (p, y + 1, w, 1, 3L, 4L, 3, 4, 2L, 5); + for (int i = 0; i < 4; i++) + for (int j = 0; j < 3; j++) + for (int k = 0; k < 2; k++) + if (a[i][j][k].t != a2[i][j][k]) + __builtin_abort (); + for (int i = 0; i < 5; i++) + if (y[i].t != y2[i]) + __builtin_abort (); + for (int i = 0; i < 10; i++) + if (z[i].t != z2[i]) + __builtin_abort (); + if (w[0][0].t != ~0x249249L || w[0][1].t != ~0x249249L) + __builtin_abort (); + S<2> s; + s.foo (1, 3L, 4L, 3, 4, 2L, 5); + for (int i = 0; i < 9; i++) + if (s.a[i].t != (i < 4 ? 0x55555555ULL : 0)) + __builtin_abort (); + for (int i = 0; i < 4; i++) + for (int j = 0; j < 3; j++) + for (int k = 0; k < 2; k++) + if (a3[i][j][k].t != a2[i][j][k]) + __builtin_abort (); + for (int i = 0; i < 5; i++) + if (y3[i].t != y2[i]) + __builtin_abort (); + for (int i = 0; i < 10; i++) + if (s.z[i].t != z2[i]) + __builtin_abort (); + if (w3[0][0].t != ~0x249249L || w3[0][1].t != ~0x249249L) + __builtin_abort (); + if (s.b[0] != 78 || s.b[1] != 12 || s.b[2] != 22 + || s.b[3] != 84 || s.b[4] != 127) + __builtin_abort (); +} Jakub