From patchwork Wed Jun 13 18:41:09 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 929040 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-479648-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="hapnl2av"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 415bFH0jJ9z9s0W for ; Thu, 14 Jun 2018 04:41:37 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:reply-to:mime-version:content-type; q=dns; s=default; b=Lm3JkCi8Fe2LJ/s1VCN8bDjjrgXJNipE+RfnHJpUZpy AF5dO7yHfOpWOZmWkcZw+kbdGKYrQWf/ZHc7xnHh76XBhcXJGe/zNdHUvwAepsA7 EiIsd2JnYOs/05jYlk8s8DqSsk9GLp84vPElPtaxMn8zgts6N0fQAVunYqbv0vzU = DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:reply-to:mime-version:content-type; s=default; bh=dC43xAIXnOQaHp+93SapSxxMIdQ=; b=hapnl2avEfQzusu3o YdvfZqb1ya2DIxOTFalEsYLLt6oulWwDudNjZeVhhbinCUX1Sx9Wp5qxd/bBxHCQ XL3zk/ic+pkCSH1h/Y9EvJ7GVSR1sjJ/tZQXaWFgerf6QtDRAu/Njw4gBAIiapdz 6tlAhIpDrTggO/+/gpggAA78b8= Received: (qmail 10495 invoked by alias); 13 Jun 2018 18:41:23 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 10469 invoked by uid 89); 13 Jun 2018 18:41:22 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-10.9 required=5.0 tests=BAYES_00, GIT_PATCH_2, GIT_PATCH_3, KAM_LAZY_DOMAIN_SECURITY, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=tre, SPC, spc, xy X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 13 Jun 2018 18:41:15 +0000 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id EB5FD8762D for ; Wed, 13 Jun 2018 18:41:13 +0000 (UTC) Received: from tucnak.zalov.cz (ovpn-117-37.ams2.redhat.com [10.36.117.37]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 0AA0B2A2C6 for ; Wed, 13 Jun 2018 18:41:12 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.15.2/8.15.2) with ESMTP id w5DIfAak008152 for ; Wed, 13 Jun 2018 20:41:10 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.15.2/8.15.2/Submit) id w5DIf9vv008151 for gcc-patches@gcc.gnu.org; Wed, 13 Jun 2018 20:41:09 +0200 Date: Wed, 13 Jun 2018 20:41:09 +0200 From: Jakub Jelinek To: gcc-patches@gcc.gnu.org Subject: [gomp5] Support OpenMP 5.0 iterators in depend clauses Message-ID: <20180613184109.GM7166@tucnak> Reply-To: Jakub Jelinek MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.9.2 (2017-12-15) X-IsSubscribed: yes Hi! The following patch adds support for depend clause iterators. Tested on x86_64-linux, committed to gomp-5_0-branch. 2018-06-13 Jakub Jelinek * gimplify.c (gimplify_omp_depend): New function. (gimplify_scan_omp_clauses): Gimplify depend clauses with iterators. * omp-low.c (lower_depend_clauses): If OMP_CLAUSE_DEPEND_LAST is seen, assume lowering is done already and return early. Set kind on artificial depend clause to OMP_CLAUSE_DEPEND_LAST. * tree-pretty-print.c (dump_omp_iterators): New function. (dump_omp_clause): Print iterators in depend clauses. Print __internal__ for OMP_CLAUSE_DEPEND_LAST. gcc/c/ * c-parser.c (c_parser_omp_iterators): New function. (c_parser_omp_clause_depend): Parse iterator modifier and handle iterators. * c-typeck.c (handle_omp_array_sections): Handle depend clauses with iterators. (struct c_find_omp_var_s): New type. (c_find_omp_var_r): New function. (c_omp_finish_iterators): New function. (c_finish_omp_clauses): Handle depend clauses with iterators. gcc/cp/ * parser.c (cp_parser_omp_iterators): New function. (cp_parser_omp_clause_depend): Parse iterator modifier and handle iterators. * semantics.c (handle_omp_array_sections): Handle depend clauses with iterators. (cp_omp_finish_iterators): New function. (finish_omp_clauses): Handle depend clauses with iterators. * pt.c (tsubst_omp_clause_decl): Add iterators_cache argument. Adjust recursive calls. Handle iterators. (tsubst_omp_clauses): Adjust tsubst_omp_clause_decl callers. gcc/testsuite/ * c-c++-common/gomp/depend-iterator-1.c: New test. * c-c++-common/gomp/depend-iterator-2.c: New test. * g++.dg/gomp/depend-iterator-1.C: New test. * g++.dg/gomp/depend-iterator-2.C: New test. libgomp/ * testsuite/libgomp.c-c++-common/depend-iterator-1.c: New test. * testsuite/libgomp.c++/depend-iterator-1.C: New test. Jakub --- gcc/gimplify.c.jj 2018-06-05 15:00:56.217957674 +0200 +++ gcc/gimplify.c 2018-06-12 11:45:41.817981609 +0200 @@ -7556,6 +7556,368 @@ find_decl_expr (tree *tp, int *walk_subt return NULL_TREE; } +/* If *LIST_P contains any OpenMP depend clauses with iterators, + lower all the depend clauses by populating corresponding depend + array. Returns 0 if there are no such depend clauses, or + 2 if all depend clauses should be removed, 1 otherwise. */ + +static int +gimplify_omp_depend (tree *list_p, gimple_seq *pre_p) +{ + tree c; + gimple *g; + size_t n[2] = { 0, 0 }; + tree counts[2] = { NULL_TREE, NULL_TREE }; + tree last_iter = NULL_TREE, last_count = NULL_TREE; + size_t i; + location_t first_loc = UNKNOWN_LOCATION; + + for (c = *list_p; c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND) + { + switch (OMP_CLAUSE_DEPEND_KIND (c)) + { + case OMP_CLAUSE_DEPEND_IN: + i = 0; + break; + case OMP_CLAUSE_DEPEND_OUT: + case OMP_CLAUSE_DEPEND_INOUT: + case OMP_CLAUSE_DEPEND_MUTEXINOUTSET: + i = 1; + break; + case OMP_CLAUSE_DEPEND_SOURCE: + case OMP_CLAUSE_DEPEND_SINK: + continue; + default: + gcc_unreachable (); + } + tree t = OMP_CLAUSE_DECL (c); + if (first_loc == UNKNOWN_LOCATION) + first_loc = OMP_CLAUSE_LOCATION (c); + if (TREE_CODE (t) == TREE_LIST + && TREE_PURPOSE (t) + && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC) + { + if (TREE_PURPOSE (t) != last_iter) + { + tree tcnt = size_one_node; + for (tree it = TREE_PURPOSE (t); it; it = TREE_CHAIN (it)) + { + if (gimplify_expr (&TREE_VEC_ELT (it, 1), pre_p, NULL, + is_gimple_val, fb_rvalue) == GS_ERROR + || gimplify_expr (&TREE_VEC_ELT (it, 2), pre_p, NULL, + is_gimple_val, fb_rvalue) == GS_ERROR + || (gimplify_expr (&TREE_VEC_ELT (it, 3), pre_p, NULL, + is_gimple_val, fb_rvalue) + == GS_ERROR)) + return 2; + tree var = TREE_VEC_ELT (it, 0); + tree begin = TREE_VEC_ELT (it, 1); + tree end = TREE_VEC_ELT (it, 2); + tree step = TREE_VEC_ELT (it, 3); + tree type = TREE_TYPE (var); + tree stype = TREE_TYPE (step); + location_t loc = DECL_SOURCE_LOCATION (var); + tree endmbegin; + /* Compute count for this iterator as + step > 0 + ? (begin < end ? (end - begin + (step - 1)) / step : 0) + : (begin > end ? (end - begin + (step + 1)) / step : 0) + and compute product of those for the entire depend + clause. */ + if (POINTER_TYPE_P (type)) + endmbegin = fold_build2_loc (loc, POINTER_DIFF_EXPR, + stype, end, begin); + else + endmbegin = fold_build2_loc (loc, MINUS_EXPR, type, + end, begin); + tree stepm1 = fold_build2_loc (loc, MINUS_EXPR, stype, + step, + build_int_cst (stype, 1)); + tree stepp1 = fold_build2_loc (loc, PLUS_EXPR, stype, step, + build_int_cst (stype, 1)); + tree pos = fold_build2_loc (loc, PLUS_EXPR, stype, + unshare_expr (endmbegin), + stepm1); + pos = fold_build2_loc (loc, TRUNC_DIV_EXPR, stype, + pos, step); + tree neg = fold_build2_loc (loc, PLUS_EXPR, stype, + endmbegin, stepp1); + neg = fold_build2_loc (loc, TRUNC_DIV_EXPR, stype, + neg, step); + tree cond = fold_build2_loc (loc, LT_EXPR, + boolean_type_node, + begin, end); + pos = fold_build3_loc (loc, COND_EXPR, stype, cond, pos, + build_int_cst (stype, 0)); + cond = fold_build2_loc (loc, LT_EXPR, boolean_type_node, + end, begin); + neg = fold_build3_loc (loc, COND_EXPR, stype, cond, neg, + build_int_cst (stype, 0)); + cond = fold_build2_loc (loc, GT_EXPR, boolean_type_node, + step, build_int_cst (stype, 0)); + tree cnt = fold_build3_loc (loc, COND_EXPR, stype, + cond, pos, neg); + cnt = fold_convert_loc (loc, sizetype, cnt); + if (gimplify_expr (&cnt, pre_p, NULL, is_gimple_val, + fb_rvalue) == GS_ERROR) + return 2; + tcnt = size_binop_loc (loc, MULT_EXPR, tcnt, cnt); + } + if (gimplify_expr (&tcnt, pre_p, NULL, is_gimple_val, + fb_rvalue) == GS_ERROR) + return 2; + last_iter = TREE_PURPOSE (t); + last_count = tcnt; + } + if (counts[i] == NULL_TREE) + counts[i] = last_count; + else + counts[i] = size_binop_loc (OMP_CLAUSE_LOCATION (c), + PLUS_EXPR, counts[i], last_count); + } + else + n[i]++; + } + if (counts[0] == NULL_TREE && counts[1] == NULL_TREE) + return 0; + for (i = 0; i < 2; i++) + { + if (counts[i] == NULL_TREE) + counts[i] = size_zero_node; + if (n[i]) + counts[i] = size_binop (PLUS_EXPR, counts[i], size_int (n[i])); + if (gimplify_expr (&counts[i], pre_p, NULL, is_gimple_val, + fb_rvalue) == GS_ERROR) + return 2; + } + + tree total = size_binop (PLUS_EXPR, counts[0], counts[1]); + if (gimplify_expr (&total, pre_p, NULL, is_gimple_val, fb_rvalue) + == GS_ERROR) + return 2; + tree totalp1 = size_binop (PLUS_EXPR, unshare_expr (total), size_int (1)); + tree type = build_array_type (ptr_type_node, build_index_type (totalp1)); + tree array = create_tmp_var_raw (type); + TREE_ADDRESSABLE (array) = 1; + if (TREE_CODE (totalp1) != INTEGER_CST) + { + if (!TYPE_SIZES_GIMPLIFIED (TREE_TYPE (array))) + gimplify_type_sizes (TREE_TYPE (array), pre_p); + if (gimplify_omp_ctxp) + { + struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp; + while (ctx + && (ctx->region_type == ORT_WORKSHARE + || ctx->region_type == ORT_SIMD + || ctx->region_type == ORT_ACC)) + ctx = ctx->outer_context; + if (ctx) + omp_add_variable (ctx, array, GOVD_LOCAL | GOVD_SEEN); + } + gimplify_vla_decl (array, pre_p); + } + else + gimple_add_tmp_var (array); + tree r = build4 (ARRAY_REF, ptr_type_node, array, size_int (0), NULL_TREE, + NULL_TREE); + tree tem = build2 (MODIFY_EXPR, void_type_node, r, + fold_convert (ptr_type_node, total)); + gimplify_and_add (tem, pre_p); + r = build4 (ARRAY_REF, ptr_type_node, array, size_int (1), NULL_TREE, + NULL_TREE); + tem = build2 (MODIFY_EXPR, void_type_node, r, counts[1]); + gimplify_and_add (tem, pre_p); + + tree cnts[2]; + for (i = 0; i < 2; i++) + { + cnts[i] = create_tmp_var (sizetype, NULL); + g = gimple_build_assign (cnts[i], i == 0 ? size_int (2) + : size_binop (PLUS_EXPR, counts[0], + size_int (2))); + gimple_seq_add_stmt (pre_p, g); + } + + last_iter = NULL_TREE; + tree last_bind = NULL_TREE; + tree *last_body = NULL; + for (c = *list_p; c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND) + { + switch (OMP_CLAUSE_DEPEND_KIND (c)) + { + case OMP_CLAUSE_DEPEND_IN: + i = 0; + break; + case OMP_CLAUSE_DEPEND_OUT: + case OMP_CLAUSE_DEPEND_INOUT: + case OMP_CLAUSE_DEPEND_MUTEXINOUTSET: + i = 1; + break; + case OMP_CLAUSE_DEPEND_SOURCE: + case OMP_CLAUSE_DEPEND_SINK: + continue; + default: + gcc_unreachable (); + } + tree t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) == TREE_LIST + && TREE_PURPOSE (t) + && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC) + { + if (TREE_PURPOSE (t) != last_iter) + { + if (last_bind) + gimplify_and_add (last_bind, pre_p); + tree block = TREE_VEC_ELT (TREE_PURPOSE (t), 4); + last_bind = build3 (BIND_EXPR, void_type_node, + BLOCK_VARS (block), NULL, block); + TREE_SIDE_EFFECTS (last_bind) = 1; + SET_EXPR_LOCATION (last_bind, OMP_CLAUSE_LOCATION (c)); + tree *p = &BIND_EXPR_BODY (last_bind); + for (tree it = TREE_PURPOSE (t); it; it = TREE_CHAIN (it)) + { + tree var = TREE_VEC_ELT (it, 0); + tree begin = TREE_VEC_ELT (it, 1); + tree end = TREE_VEC_ELT (it, 2); + tree step = TREE_VEC_ELT (it, 3); + tree type = TREE_TYPE (var); + tree stype = TREE_TYPE (step); + location_t loc = DECL_SOURCE_LOCATION (var); + /* Emit: + var = begin; + goto cond_label; + beg_label: + ... + var = var + step; + cond_label: + if (step > 0) { + if (var < end) goto beg_label; + } else { + if (var > end) goto beg_label; + } + for each iterator, with inner iterators added to + the ... above. */ + tree beg_label = create_artificial_label (loc); + tree cond_label = NULL_TREE; + tem = build2_loc (loc, MODIFY_EXPR, void_type_node, + var, begin); + append_to_statement_list_force (tem, p); + tem = build_and_jump (&cond_label); + append_to_statement_list_force (tem, p); + tem = build1 (LABEL_EXPR, void_type_node, beg_label); + append_to_statement_list (tem, p); + tree bind = build3 (BIND_EXPR, void_type_node, NULL_TREE, + NULL_TREE, NULL_TREE); + TREE_SIDE_EFFECTS (bind) = 1; + SET_EXPR_LOCATION (bind, loc); + append_to_statement_list_force (bind, p); + if (POINTER_TYPE_P (type)) + tem = build2_loc (loc, POINTER_PLUS_EXPR, type, + var, fold_convert_loc (loc, sizetype, + step)); + else + tem = build2_loc (loc, PLUS_EXPR, type, var, step); + tem = build2_loc (loc, MODIFY_EXPR, void_type_node, + var, tem); + append_to_statement_list_force (tem, p); + tem = build1 (LABEL_EXPR, void_type_node, cond_label); + append_to_statement_list (tem, p); + tree cond = fold_build2_loc (loc, LT_EXPR, + boolean_type_node, + var, end); + tree pos + = fold_build3_loc (loc, COND_EXPR, void_type_node, + cond, build_and_jump (&beg_label), + void_node); + cond = fold_build2_loc (loc, GT_EXPR, boolean_type_node, + var, end); + tree neg + = fold_build3_loc (loc, COND_EXPR, void_type_node, + cond, build_and_jump (&beg_label), + void_node); + cond = fold_build2_loc (loc, GT_EXPR, boolean_type_node, + step, build_int_cst (stype, 0)); + tem = fold_build3_loc (loc, COND_EXPR, void_type_node, + cond, pos, neg); + append_to_statement_list_force (tem, p); + p = &BIND_EXPR_BODY (bind); + } + last_body = p; + } + last_iter = TREE_PURPOSE (t); + if (TREE_CODE (TREE_VALUE (t)) == COMPOUND_EXPR) + { + append_to_statement_list (TREE_OPERAND (TREE_VALUE (t), + 0), last_body); + TREE_VALUE (t) = TREE_OPERAND (TREE_VALUE (t), 1); + } + if (error_operand_p (TREE_VALUE (t))) + return 2; + TREE_VALUE (t) = build_fold_addr_expr (TREE_VALUE (t)); + r = build4 (ARRAY_REF, ptr_type_node, array, cnts[i], + NULL_TREE, NULL_TREE); + tem = build2_loc (OMP_CLAUSE_LOCATION (c), MODIFY_EXPR, + void_type_node, r, TREE_VALUE (t)); + append_to_statement_list_force (tem, last_body); + tem = build2_loc (OMP_CLAUSE_LOCATION (c), MODIFY_EXPR, + void_type_node, cnts[i], + size_binop (PLUS_EXPR, cnts[i], size_int (1))); + append_to_statement_list_force (tem, last_body); + TREE_VALUE (t) = null_pointer_node; + } + else + { + if (last_bind) + { + gimplify_and_add (last_bind, pre_p); + last_bind = NULL_TREE; + } + if (TREE_CODE (OMP_CLAUSE_DECL (c)) == COMPOUND_EXPR) + { + gimplify_expr (&TREE_OPERAND (OMP_CLAUSE_DECL (c), 0), pre_p, + NULL, is_gimple_val, fb_rvalue); + OMP_CLAUSE_DECL (c) = TREE_OPERAND (OMP_CLAUSE_DECL (c), 1); + } + if (error_operand_p (OMP_CLAUSE_DECL (c))) + return 2; + OMP_CLAUSE_DECL (c) = build_fold_addr_expr (OMP_CLAUSE_DECL (c)); + if (gimplify_expr (&OMP_CLAUSE_DECL (c), pre_p, NULL, + is_gimple_val, fb_rvalue) == GS_ERROR) + return 2; + r = build4 (ARRAY_REF, ptr_type_node, array, cnts[i], + NULL_TREE, NULL_TREE); + tem = build2 (MODIFY_EXPR, void_type_node, r, OMP_CLAUSE_DECL (c)); + gimplify_and_add (tem, pre_p); + g = gimple_build_assign (cnts[i], size_binop (PLUS_EXPR, cnts[i], + size_int (1))); + gimple_seq_add_stmt (pre_p, g); + } + } + if (last_bind) + gimplify_and_add (last_bind, pre_p); + tree cond = build2_loc (first_loc, NE_EXPR, boolean_type_node, cnts[0], + size_binop_loc (first_loc, PLUS_EXPR, counts[0], + size_int (2))); + cond = build2_loc (first_loc, TRUTH_OR_EXPR, boolean_type_node, cond, + build2_loc (first_loc, NE_EXPR, boolean_type_node, + cnts[1], + size_binop_loc (first_loc, PLUS_EXPR, + totalp1, size_int (1)))); + tem = build3_loc (first_loc, COND_EXPR, void_type_node, cond, + build_call_expr_loc (first_loc, + builtin_decl_explicit (BUILT_IN_TRAP), + 0), void_node); + gimplify_and_add (tem, pre_p); + c = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE_DEPEND); + OMP_CLAUSE_DEPEND_KIND (c) = OMP_CLAUSE_DEPEND_LAST; + OMP_CLAUSE_DECL (c) = build_fold_addr_expr (array); + OMP_CLAUSE_CHAIN (c) = *list_p; + *list_p = c; + return 1; +} + /* Scan the OMP clauses in *LIST_P, installing mappings into a new and previous omp contexts. */ @@ -7568,6 +7930,7 @@ gimplify_scan_omp_clauses (tree *list_p, tree c; hash_map *struct_map_to_clause = NULL; tree *prev_list_p = NULL; + int handled_depend_iterators = -1; ctx = new_omp_context (region_type); outer_ctx = ctx->outer_context; @@ -8330,6 +8693,14 @@ gimplify_scan_omp_clauses (tree *list_p, } else if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SOURCE) break; + if (handled_depend_iterators == -1) + handled_depend_iterators = gimplify_omp_depend (list_p, pre_p); + if (handled_depend_iterators) + { + if (handled_depend_iterators == 2) + remove = true; + break; + } if (TREE_CODE (OMP_CLAUSE_DECL (c)) == COMPOUND_EXPR) { gimplify_expr (&TREE_OPERAND (OMP_CLAUSE_DECL (c), 0), pre_p, --- gcc/omp-low.c.jj 2018-06-05 15:00:56.232957694 +0200 +++ gcc/omp-low.c 2018-06-08 12:12:34.377111135 +0200 @@ -7347,6 +7347,9 @@ lower_depend_clauses (tree *pclauses, gi if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND) switch (OMP_CLAUSE_DEPEND_KIND (c)) { + case OMP_CLAUSE_DEPEND_LAST: + /* Lowering already done at gimplification. */ + return; case OMP_CLAUSE_DEPEND_IN: n_in++; break; @@ -7390,6 +7393,7 @@ lower_depend_clauses (tree *pclauses, gi } } c = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE_DEPEND); + OMP_CLAUSE_DEPEND_KIND (c) = OMP_CLAUSE_DEPEND_LAST; OMP_CLAUSE_DECL (c) = build_fold_addr_expr (array); OMP_CLAUSE_CHAIN (c) = *pclauses; *pclauses = c; --- gcc/tree-pretty-print.c.jj 2018-06-05 15:00:56.232957694 +0200 +++ gcc/tree-pretty-print.c 2018-06-08 10:57:43.223983430 +0200 @@ -382,6 +382,31 @@ dump_array_domain (pretty_printer *pp, t } +/* Dump OpenMP iterators ITER. */ + +static void +dump_omp_iterators (pretty_printer *pp, tree iter, int spc, dump_flags_t flags) +{ + pp_string (pp, "iterator("); + for (tree it = iter; it; it = TREE_CHAIN (it)) + { + if (it != iter) + pp_string (pp, ", "); + dump_generic_node (pp, TREE_TYPE (TREE_VEC_ELT (it, 0)), spc, flags, + false); + pp_space (pp); + dump_generic_node (pp, TREE_VEC_ELT (it, 0), spc, flags, false); + pp_equal (pp); + dump_generic_node (pp, TREE_VEC_ELT (it, 1), spc, flags, false); + pp_colon (pp); + dump_generic_node (pp, TREE_VEC_ELT (it, 2), spc, flags, false); + pp_colon (pp); + dump_generic_node (pp, TREE_VEC_ELT (it, 3), spc, flags, false); + } + pp_right_paren (pp); +} + + /* Dump OpenMP clause CLAUSE. PP, CLAUSE, SPC and FLAGS are as in dump_generic_node. */ @@ -650,20 +675,23 @@ dump_omp_clause (pretty_printer *pp, tre switch (OMP_CLAUSE_DEPEND_KIND (clause)) { case OMP_CLAUSE_DEPEND_IN: - pp_string (pp, "in"); + name = "in"; break; case OMP_CLAUSE_DEPEND_OUT: - pp_string (pp, "out"); + name = "out"; break; case OMP_CLAUSE_DEPEND_INOUT: - pp_string (pp, "inout"); + name = "inout"; break; case OMP_CLAUSE_DEPEND_MUTEXINOUTSET: - pp_string (pp, "mutexinoutset"); + name = "mutexinoutset"; break; case OMP_CLAUSE_DEPEND_SOURCE: pp_string (pp, "source)"); return; + case OMP_CLAUSE_DEPEND_LAST: + name = "__internal__"; + break; case OMP_CLAUSE_DEPEND_SINK: pp_string (pp, "sink:"); for (tree t = OMP_CLAUSE_DECL (clause); t; t = TREE_CHAIN (t)) @@ -689,10 +717,21 @@ dump_omp_clause (pretty_printer *pp, tre default: gcc_unreachable (); } - pp_colon (pp); - dump_generic_node (pp, OMP_CLAUSE_DECL (clause), - spc, flags, false); - pp_right_paren (pp); + { + tree t = OMP_CLAUSE_DECL (clause); + if (TREE_CODE (t) == TREE_LIST + && TREE_PURPOSE (t) + && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC) + { + dump_omp_iterators (pp, TREE_PURPOSE (t), spc, flags); + pp_colon (pp); + t = TREE_VALUE (t); + } + pp_string (pp, name); + pp_colon (pp); + dump_generic_node (pp, t, spc, flags, false); + pp_right_paren (pp); + } break; case OMP_CLAUSE_MAP: --- gcc/c/c-parser.c.jj 2018-06-05 15:00:56.357957856 +0200 +++ gcc/c/c-parser.c 2018-06-13 13:07:02.194649345 +0200 @@ -13802,6 +13802,106 @@ c_parser_omp_clause_depend_sink (c_parse return u; } +/* OpenMP 5.0: + iterators ( iterators-definition ) + + iterators-definition: + iterator-specifier + iterator-specifier , iterators-definition + + iterator-specifier: + identifier = range-specification + iterator-type identifier = range-specification + + range-specification: + begin : end + begin : end : step */ + +static tree +c_parser_omp_iterators (c_parser *parser) +{ + tree ret = NULL_TREE, *last = &ret; + c_parser_consume_token (parser); + + push_scope (); + + matching_parens parens; + if (!parens.require_open (parser)) + return error_mark_node; + + do + { + tree iter_type = NULL_TREE, type_expr = NULL_TREE; + if (c_parser_next_tokens_start_typename (parser, cla_prefer_id)) + { + struct c_type_name *type = c_parser_type_name (parser); + if (type != NULL) + iter_type = groktypename (type, &type_expr, NULL); + } + if (iter_type == NULL_TREE) + iter_type = integer_type_node; + + location_t loc = c_parser_peek_token (parser)->location; + if (!c_parser_next_token_is (parser, CPP_NAME)) + { + c_parser_error (parser, "expected identifier"); + break; + } + + tree id = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + + if (!c_parser_require (parser, CPP_EQ, "expected %<=%>")) + break; + + location_t eloc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (eloc, expr, true, false); + tree begin = expr.value; + + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + break; + + eloc = c_parser_peek_token (parser)->location; + expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (eloc, expr, true, false); + tree end = expr.value; + + tree step = integer_one_node; + if (c_parser_next_token_is (parser, CPP_COLON)) + { + c_parser_consume_token (parser); + eloc = c_parser_peek_token (parser)->location; + expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (eloc, expr, true, false); + step = expr.value; + } + + tree iter_var = build_decl (loc, VAR_DECL, id, iter_type); + DECL_ARTIFICIAL (iter_var) = 1; + DECL_CONTEXT (iter_var) = current_function_decl; + pushdecl (iter_var); + + *last = make_tree_vec (5); + TREE_VEC_ELT (*last, 0) = iter_var; + TREE_VEC_ELT (*last, 1) = begin; + TREE_VEC_ELT (*last, 2) = end; + TREE_VEC_ELT (*last, 3) = step; + last = &TREE_CHAIN (*last); + + if (c_parser_next_token_is (parser, CPP_COMMA)) + { + c_parser_consume_token (parser); + continue; + } + break; + } + while (1); + + parens.skip_until_found_close (parser); + return ret; +} + /* OpenMP 4.0: depend ( depend-kind: variable-list ) @@ -13818,14 +13918,17 @@ c_parser_omp_clause_depend (c_parser *pa { location_t clause_loc = c_parser_peek_token (parser)->location; enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INOUT; - tree nl, c; + tree nl, c, iterators = NULL_TREE; matching_parens parens; if (!parens.require_open (parser)) return list; - if (c_parser_next_token_is (parser, CPP_NAME)) + do { + if (c_parser_next_token_is_not (parser, CPP_NAME)) + goto invalid_kind; + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); if (strcmp ("in", p) == 0) kind = OMP_CLAUSE_DEPEND_IN; @@ -13839,14 +13942,29 @@ c_parser_omp_clause_depend (c_parser *pa kind = OMP_CLAUSE_DEPEND_SOURCE; else if (strcmp ("sink", p) == 0) kind = OMP_CLAUSE_DEPEND_SINK; + else if (strcmp ("iterator", p) == 0 && iterators == NULL_TREE) + { + iterators = c_parser_omp_iterators (parser); + c_parser_require (parser, CPP_COLON, "expected %<:%>"); + continue; + } else goto invalid_kind; + break; } - else - goto invalid_kind; + while (1); c_parser_consume_token (parser); + if (iterators + && (kind == OMP_CLAUSE_DEPEND_SOURCE || kind == OMP_CLAUSE_DEPEND_SINK)) + { + pop_scope (); + error_at (clause_loc, "% modifier incompatible with %qs", + kind == OMP_CLAUSE_DEPEND_SOURCE ? "source" : "sink"); + iterators = NULL_TREE; + } + if (kind == OMP_CLAUSE_DEPEND_SOURCE) { c = build_omp_clause (clause_loc, OMP_CLAUSE_DEPEND); @@ -13867,8 +13985,22 @@ c_parser_omp_clause_depend (c_parser *pa nl = c_parser_omp_variable_list (parser, clause_loc, OMP_CLAUSE_DEPEND, list); + if (iterators) + { + tree block = pop_scope (); + if (iterators == error_mark_node) + iterators = NULL_TREE; + else + TREE_VEC_ELT (iterators, 4) = block; + } + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) - OMP_CLAUSE_DEPEND_KIND (c) = kind; + { + OMP_CLAUSE_DEPEND_KIND (c) = kind; + if (iterators) + OMP_CLAUSE_DECL (c) + = build_tree_list (iterators, OMP_CLAUSE_DECL (c)); + } } parens.skip_until_found_close (parser); @@ -13878,6 +14010,8 @@ c_parser_omp_clause_depend (c_parser *pa c_parser_error (parser, "invalid depend kind"); resync_fail: parens.skip_until_found_close (parser); + if (iterators) + pop_scope (); return list; } --- gcc/c/c-typeck.c.jj 2018-06-05 10:59:17.886728884 +0200 +++ gcc/c/c-typeck.c 2018-06-13 18:21:54.220430042 +0200 @@ -12747,7 +12747,13 @@ handle_omp_array_sections (tree c, enum bool maybe_zero_len = false; unsigned int first_non_one = 0; auto_vec types; - tree first = handle_omp_array_sections_1 (c, OMP_CLAUSE_DECL (c), types, + tree *tp = &OMP_CLAUSE_DECL (c); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + && TREE_CODE (*tp) == TREE_LIST + && TREE_PURPOSE (*tp) + && TREE_CODE (TREE_PURPOSE (*tp)) == TREE_VEC) + tp = &TREE_VALUE (*tp); + tree first = handle_omp_array_sections_1 (c, *tp, types, maybe_zero_len, first_non_one, ort); if (first == error_mark_node) @@ -12756,7 +12762,7 @@ handle_omp_array_sections (tree c, enum return false; if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND) { - tree t = OMP_CLAUSE_DECL (c); + tree t = *tp; tree tem = NULL_TREE; /* Need to evaluate side effects in the length expressions if any. */ @@ -12775,7 +12781,7 @@ handle_omp_array_sections (tree c, enum if (tem) first = build2 (COMPOUND_EXPR, TREE_TYPE (first), tem, first); first = c_fully_fold (first, false, NULL, true); - OMP_CLAUSE_DECL (c) = first; + *tp = first; } else { @@ -13038,6 +13044,162 @@ c_find_omp_placeholder_r (tree *tp, int return NULL_TREE; } +/* Similarly, but also walk aggregate fields. */ + +struct c_find_omp_var_s { tree var; hash_set *pset; }; + +static tree +c_find_omp_var_r (tree *tp, int *, void *data) +{ + if (*tp == ((struct c_find_omp_var_s *) data)->var) + return *tp; + if (RECORD_OR_UNION_TYPE_P (*tp)) + { + tree field; + hash_set *pset = ((struct c_find_omp_var_s *) data)->pset; + + for (field = TYPE_FIELDS (*tp); field; + field = DECL_CHAIN (field)) + if (TREE_CODE (field) == FIELD_DECL) + { + tree ret = walk_tree (&DECL_FIELD_OFFSET (field), + c_find_omp_var_r, data, pset); + if (ret) + return ret; + ret = walk_tree (&DECL_SIZE (field), c_find_omp_var_r, data, pset); + if (ret) + return ret; + ret = walk_tree (&DECL_SIZE_UNIT (field), c_find_omp_var_r, data, + pset); + if (ret) + return ret; + ret = walk_tree (&TREE_TYPE (field), c_find_omp_var_r, data, pset); + if (ret) + return ret; + } + } + else if (INTEGRAL_TYPE_P (*tp)) + return walk_tree (&TYPE_MAX_VALUE (*tp), c_find_omp_var_r, data, + ((struct c_find_omp_var_s *) data)->pset); + return NULL_TREE; +} + +/* Finish OpenMP iterators ITER. Return true if they are errorneous + and clauses containing them should be removed. */ + +static bool +c_omp_finish_iterators (tree iter) +{ + bool ret = false; + for (tree it = iter; it; it = TREE_CHAIN (it)) + { + tree var = TREE_VEC_ELT (it, 0); + tree begin = TREE_VEC_ELT (it, 1); + tree end = TREE_VEC_ELT (it, 2); + tree step = TREE_VEC_ELT (it, 3); + tree type = TREE_TYPE (var); + location_t loc = DECL_SOURCE_LOCATION (var); + if (type == error_mark_node) + { + ret = true; + continue; + } + if (!INTEGRAL_TYPE_P (type) && !POINTER_TYPE_P (type)) + { + error_at (loc, "iterator %qD has neither integral nor pointer type", + var); + ret = true; + continue; + } + else if (TYPE_ATOMIC (type)) + { + error_at (loc, "iterator %qD has %<_Atomic%> qualified type", var); + ret = true; + continue; + } + else if (TYPE_READONLY (type)) + { + error_at (loc, "iterator %qD has const qualified type", var); + ret = true; + continue; + } + + begin = c_fully_fold (build_c_cast (loc, type, begin), false, NULL); + end = c_fully_fold (build_c_cast (loc, type, end), false, NULL); + tree stype = POINTER_TYPE_P (type) ? sizetype : type; + step = c_fully_fold (build_c_cast (loc, stype, step), false, NULL); + if (POINTER_TYPE_P (type)) + { + begin = save_expr (begin); + step = pointer_int_sum (loc, PLUS_EXPR, begin, step); + step = fold_build2_loc (loc, MINUS_EXPR, sizetype, + fold_convert (sizetype, step), + fold_convert (sizetype, begin)); + step = fold_convert (ssizetype, step); + } + if (integer_zerop (step)) + { + error_at (loc, "iterator %qD has zero step", var); + ret = true; + continue; + } + + if (begin == error_mark_node + || end == error_mark_node + || step == error_mark_node) + { + ret = true; + continue; + } + hash_set pset; + tree it2; + for (it2 = TREE_CHAIN (it); it2; it2 = TREE_CHAIN (it2)) + { + tree var2 = TREE_VEC_ELT (it2, 0); + tree begin2 = TREE_VEC_ELT (it2, 1); + tree end2 = TREE_VEC_ELT (it2, 2); + tree step2 = TREE_VEC_ELT (it2, 3); + tree type2 = TREE_TYPE (var2); + location_t loc2 = DECL_SOURCE_LOCATION (var2); + struct c_find_omp_var_s data = { var, &pset }; + if (walk_tree (&type2, c_find_omp_var_r, &data, &pset)) + { + error_at (loc2, + "type of iterator %qD refers to outer iterator %qD", + var2, var); + break; + } + else if (walk_tree (&begin2, c_find_omp_var_r, &data, &pset)) + { + error_at (EXPR_LOC_OR_LOC (begin2, loc2), + "begin expression refers to outer iterator %qD", var); + break; + } + else if (walk_tree (&end2, c_find_omp_var_r, &data, &pset)) + { + error_at (EXPR_LOC_OR_LOC (end2, loc2), + "end expression refers to outer iterator %qD", var); + break; + } + else if (walk_tree (&step2, c_find_omp_var_r, &data, &pset)) + { + error_at (EXPR_LOC_OR_LOC (step2, loc2), + "step expression refers to outer iterator %qD", var); + break; + } + } + if (it2) + { + ret = true; + continue; + } + TREE_VEC_ELT (it, 1) = begin; + TREE_VEC_ELT (it, 2) = end; + TREE_VEC_ELT (it, 3) = step; + } + return ret; +} + /* For all elements of CLAUSES, validate them against their constraints. Remove any elements from the list that are invalid. */ @@ -13055,6 +13217,8 @@ c_finish_omp_clauses (tree clauses, enum bool ordered_seen = false; tree schedule_clause = NULL_TREE; bool oacc_async = false; + tree last_iterators = NULL_TREE; + bool last_iterators_remove = false; bitmap_obstack_initialize (NULL); bitmap_initialize (&generic_head, &bitmap_default_obstack); @@ -13589,6 +13753,20 @@ c_finish_omp_clauses (tree clauses, enum } break; } + if (TREE_CODE (t) == TREE_LIST + && TREE_PURPOSE (t) + && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC) + { + if (TREE_PURPOSE (t) != last_iterators) + last_iterators_remove + = c_omp_finish_iterators (TREE_PURPOSE (t)); + last_iterators = TREE_PURPOSE (t); + t = TREE_VALUE (t); + if (last_iterators_remove) + t = error_mark_node; + } + else + last_iterators = NULL_TREE; if (TREE_CODE (t) == TREE_LIST) { if (handle_omp_array_sections (c, ort)) --- gcc/cp/parser.c.jj 2018-06-04 18:17:54.995533519 +0200 +++ gcc/cp/parser.c 2018-06-13 16:26:27.294958834 +0200 @@ -33598,6 +33598,118 @@ cp_parser_omp_clause_depend_sink (cp_par return list; } +/* OpenMP 5.0: + iterators ( iterators-definition ) + + iterators-definition: + iterator-specifier + iterator-specifier , iterators-definition + + iterator-specifier: + identifier = range-specification + iterator-type identifier = range-specification + + range-specification: + begin : end + begin : end : step */ + +static tree +cp_parser_omp_iterators (cp_parser *parser) +{ + tree ret = NULL_TREE, *last = &ret; + cp_lexer_consume_token (parser->lexer); + + matching_parens parens; + if (!parens.require_open (parser)) + return error_mark_node; + + bool saved_colon_corrects_to_scope_p + = parser->colon_corrects_to_scope_p; + bool saved_colon_doesnt_start_class_def_p + = parser->colon_doesnt_start_class_def_p; + + do + { + tree iter_type; + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_EQ)) + iter_type = integer_type_node; + else + { + const char *saved_message + = parser->type_definition_forbidden_message; + parser->type_definition_forbidden_message + = G_("types may not be defined in iterator type"); + + iter_type = cp_parser_type_id (parser); + + parser->type_definition_forbidden_message = saved_message; + } + + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME)) + { + cp_parser_error (parser, "expected identifier"); + break; + } + + tree id = cp_parser_identifier (parser); + if (id == error_mark_node) + break; + + if (!cp_parser_require (parser, CPP_EQ, RT_EQ)) + break; + + parser->colon_corrects_to_scope_p = false; + parser->colon_doesnt_start_class_def_p = true; + tree begin = cp_parser_assignment_expression (parser); + + if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) + break; + + tree end = cp_parser_assignment_expression (parser); + + tree step = integer_one_node; + if (cp_lexer_next_token_is (parser->lexer, CPP_COLON)) + { + cp_lexer_consume_token (parser->lexer); + step = cp_parser_assignment_expression (parser); + } + + tree iter_var = build_decl (loc, VAR_DECL, id, iter_type); + DECL_ARTIFICIAL (iter_var) = 1; + DECL_CONTEXT (iter_var) = current_function_decl; + pushdecl (iter_var); + + *last = make_tree_vec (5); + TREE_VEC_ELT (*last, 0) = iter_var; + TREE_VEC_ELT (*last, 1) = begin; + TREE_VEC_ELT (*last, 2) = end; + TREE_VEC_ELT (*last, 3) = step; + last = &TREE_CHAIN (*last); + + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + { + cp_lexer_consume_token (parser->lexer); + continue; + } + break; + } + while (1); + + parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; + parser->colon_doesnt_start_class_def_p + = saved_colon_doesnt_start_class_def_p; + + if (!parens.require_close (parser)) + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + return ret; +} + /* OpenMP 4.0: depend ( depend-kind : variable-list ) @@ -33612,15 +33724,18 @@ cp_parser_omp_clause_depend_sink (cp_par static tree cp_parser_omp_clause_depend (cp_parser *parser, tree list, location_t loc) { - tree nlist, c; + tree nlist, c, iterators = NULL_TREE; enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INOUT; matching_parens parens; if (!parens.require_open (parser)) return list; - if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + do { + if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME)) + goto invalid_kind; + tree id = cp_lexer_peek_token (parser->lexer)->u.value; const char *p = IDENTIFIER_POINTER (id); @@ -33636,14 +33751,30 @@ cp_parser_omp_clause_depend (cp_parser * kind = OMP_CLAUSE_DEPEND_SOURCE; else if (strcmp ("sink", p) == 0) kind = OMP_CLAUSE_DEPEND_SINK; + else if (strcmp ("iterator", p) == 0 && iterators == NULL_TREE) + { + begin_scope (sk_omp, NULL); + iterators = cp_parser_omp_iterators (parser); + cp_parser_require (parser, CPP_COLON, RT_COLON); + continue; + } else goto invalid_kind; + break; } - else - goto invalid_kind; + while (1); cp_lexer_consume_token (parser->lexer); + if (iterators + && (kind == OMP_CLAUSE_DEPEND_SOURCE || kind == OMP_CLAUSE_DEPEND_SINK)) + { + poplevel (0, 1, 0); + error_at (loc, "% modifier incompatible with %qs", + kind == OMP_CLAUSE_DEPEND_SOURCE ? "source" : "sink"); + iterators = NULL_TREE; + } + if (kind == OMP_CLAUSE_DEPEND_SOURCE) { c = build_omp_clause (loc, OMP_CLAUSE_DEPEND); @@ -33667,14 +33798,30 @@ cp_parser_omp_clause_depend (cp_parser * nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_DEPEND, list, NULL); + if (iterators) + { + tree block = poplevel (1, 1, 0); + if (iterators == error_mark_node) + iterators = NULL_TREE; + else + TREE_VEC_ELT (iterators, 4) = block; + } + for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) - OMP_CLAUSE_DEPEND_KIND (c) = kind; + { + OMP_CLAUSE_DEPEND_KIND (c) = kind; + if (iterators) + OMP_CLAUSE_DECL (c) + = build_tree_list (iterators, OMP_CLAUSE_DECL (c)); + } } return nlist; invalid_kind: cp_parser_error (parser, "invalid depend kind"); resync_fail: + if (iterators) + poplevel (0, 1, 0); cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, /*consume_paren=*/true); --- gcc/cp/semantics.c.jj 2018-06-05 13:55:00.982594192 +0200 +++ gcc/cp/semantics.c 2018-06-13 19:25:03.003926735 +0200 @@ -4851,7 +4851,13 @@ handle_omp_array_sections (tree c, enum bool maybe_zero_len = false; unsigned int first_non_one = 0; auto_vec types; - tree first = handle_omp_array_sections_1 (c, OMP_CLAUSE_DECL (c), types, + tree *tp = &OMP_CLAUSE_DECL (c); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND + && TREE_CODE (*tp) == TREE_LIST + && TREE_PURPOSE (*tp) + && TREE_CODE (TREE_PURPOSE (*tp)) == TREE_VEC) + tp = &TREE_VALUE (*tp); + tree first = handle_omp_array_sections_1 (c, *tp, types, maybe_zero_len, first_non_one, ort); if (first == error_mark_node) @@ -4860,7 +4866,7 @@ handle_omp_array_sections (tree c, enum return false; if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND) { - tree t = OMP_CLAUSE_DECL (c); + tree t = *tp; tree tem = NULL_TREE; if (processing_template_decl) return false; @@ -4880,7 +4886,7 @@ handle_omp_array_sections (tree c, enum } if (tem) first = build2 (COMPOUND_EXPR, TREE_TYPE (first), tem, first); - OMP_CLAUSE_DECL (c) = first; + *tp = first; } else { @@ -5842,6 +5848,125 @@ cp_finish_omp_clause_depend_sink (tree s return false; } +/* Finish OpenMP iterators ITER. Return true if they are errorneous + and clauses containing them should be removed. */ + +static bool +cp_omp_finish_iterators (tree iter) +{ + bool ret = false; + for (tree it = iter; it; it = TREE_CHAIN (it)) + { + tree var = TREE_VEC_ELT (it, 0); + tree begin = TREE_VEC_ELT (it, 1); + tree end = TREE_VEC_ELT (it, 2); + tree step = TREE_VEC_ELT (it, 3); + tree type = TREE_TYPE (var); + location_t loc = DECL_SOURCE_LOCATION (var); + if (type == error_mark_node) + { + ret = true; + continue; + } + if (type_dependent_expression_p (var)) + continue; + if (!INTEGRAL_TYPE_P (type) && !POINTER_TYPE_P (type)) + { + error_at (loc, "iterator %qD has neither integral nor pointer type", + var); + ret = true; + continue; + } + else if (TYPE_READONLY (type)) + { + error_at (loc, "iterator %qD has const qualified type", var); + ret = true; + continue; + } + + begin = mark_rvalue_use (begin); + end = mark_rvalue_use (end); + step = mark_rvalue_use (step); + begin = cp_build_c_cast (type, begin, tf_warning_or_error); + end = cp_build_c_cast (type, end, tf_warning_or_error); + tree stype = POINTER_TYPE_P (type) ? sizetype : type; + step = cp_build_c_cast (stype, step, tf_warning_or_error); + if (POINTER_TYPE_P (type) && !processing_template_decl) + { + begin = save_expr (begin); + step = pointer_int_sum (loc, PLUS_EXPR, begin, step); + step = fold_build2_loc (loc, MINUS_EXPR, sizetype, + fold_convert (sizetype, step), + fold_convert (sizetype, begin)); + step = fold_convert (ssizetype, step); + } + if (!processing_template_decl) + { + begin = maybe_constant_value (begin); + end = maybe_constant_value (end); + step = maybe_constant_value (step); + } + if (integer_zerop (step)) + { + error_at (loc, "iterator %qD has zero step", var); + ret = true; + continue; + } + + if (begin == error_mark_node + || end == error_mark_node + || step == error_mark_node) + { + ret = true; + continue; + } + + if (!processing_template_decl) + { + begin = fold_build_cleanup_point_expr (TREE_TYPE (begin), begin); + end = fold_build_cleanup_point_expr (TREE_TYPE (end), end); + step = fold_build_cleanup_point_expr (TREE_TYPE (step), step); + } + hash_set pset; + tree it2; + for (it2 = TREE_CHAIN (it); it2; it2 = TREE_CHAIN (it2)) + { + tree var2 = TREE_VEC_ELT (it2, 0); + tree begin2 = TREE_VEC_ELT (it2, 1); + tree end2 = TREE_VEC_ELT (it2, 2); + tree step2 = TREE_VEC_ELT (it2, 3); + location_t loc2 = DECL_SOURCE_LOCATION (var2); + if (cp_walk_tree (&begin2, find_omp_placeholder_r, var, &pset)) + { + error_at (EXPR_LOC_OR_LOC (begin2, loc2), + "begin expression refers to outer iterator %qD", var); + break; + } + else if (cp_walk_tree (&end2, find_omp_placeholder_r, var, &pset)) + { + error_at (EXPR_LOC_OR_LOC (end2, loc2), + "end expression refers to outer iterator %qD", var); + break; + } + else if (cp_walk_tree (&step2, find_omp_placeholder_r, var, &pset)) + { + error_at (EXPR_LOC_OR_LOC (step2, loc2), + "step expression refers to outer iterator %qD", var); + break; + } + } + if (it2) + { + ret = true; + continue; + } + TREE_VEC_ELT (it, 1) = begin; + TREE_VEC_ELT (it, 2) = end; + TREE_VEC_ELT (it, 3) = step; + } + return ret; +} + /* For all elements of CLAUSES, validate them vs OpenMP constraints. Remove any elements from the list that are invalid. */ @@ -5856,6 +5981,8 @@ finish_omp_clauses (tree clauses, enum c bool copyprivate_seen = false; bool ordered_seen = false; bool oacc_async = false; + tree last_iterators = NULL_TREE; + bool last_iterators_remove = false; bitmap_obstack_initialize (NULL); bitmap_initialize (&generic_head, &bitmap_default_obstack); @@ -6565,7 +6692,7 @@ finish_omp_clauses (tree clauses, enum c else { t = mark_rvalue_use (t); - if (!processing_template_decl) + if (!processing_template_decl) t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (c) = t; } @@ -6642,6 +6769,8 @@ finish_omp_clauses (tree clauses, enum c "be positive constant integer expression"); remove = true; } + else + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); } OMP_CLAUSE_ALIGNED_ALIGNMENT (c) = t; } @@ -6688,6 +6817,21 @@ finish_omp_clauses (tree clauses, enum c remove = true; break; } + if (TREE_CODE (t) == TREE_LIST + && TREE_PURPOSE (t) + && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC) + { + if (TREE_PURPOSE (t) != last_iterators) + last_iterators_remove + = cp_omp_finish_iterators (TREE_PURPOSE (t)); + last_iterators = TREE_PURPOSE (t); + t = TREE_VALUE (t); + if (last_iterators_remove) + t = error_mark_node; + } + else + last_iterators = NULL_TREE; + if (TREE_CODE (t) == TREE_LIST) { if (handle_omp_array_sections (c, ort)) @@ -6703,7 +6847,7 @@ finish_omp_clauses (tree clauses, enum c " clauses"); remove = true; } - else if (processing_template_decl && TREE_CODE (t) != OVERLOAD) + else if (processing_template_decl && TREE_CODE (t) != OVERLOAD) break; else if (!lvalue_p (t)) { --- gcc/cp/pt.c.jj 2018-06-04 18:17:53.478531126 +0200 +++ gcc/cp/pt.c 2018-06-13 17:33:22.060761294 +0200 @@ -15941,11 +15941,49 @@ tsubst_copy (tree t, tree args, tsubst_f static tree tsubst_omp_clause_decl (tree decl, tree args, tsubst_flags_t complain, - tree in_decl) + tree in_decl, tree *iterator_cache) { if (decl == NULL_TREE) return NULL_TREE; + /* Handle OpenMP iterators. */ + if (TREE_CODE (decl) == TREE_LIST + && TREE_PURPOSE (decl) + && TREE_CODE (TREE_PURPOSE (decl)) == TREE_VEC) + { + tree ret; + if (iterator_cache[0] == TREE_PURPOSE (decl)) + ret = iterator_cache[1]; + else + { + tree *tp = &ret; + begin_scope (sk_omp, NULL); + for (tree it = TREE_PURPOSE (decl); it; it = TREE_CHAIN (it)) + { + *tp = copy_node (it); + TREE_VEC_ELT (*tp, 0) + = tsubst_decl (TREE_VEC_ELT (it, 0), args, complain); + TREE_VEC_ELT (*tp, 1) + = tsubst_expr (TREE_VEC_ELT (it, 1), args, complain, in_decl, + /*integral_constant_expression_p=*/false); + TREE_VEC_ELT (*tp, 2) + = tsubst_expr (TREE_VEC_ELT (it, 2), args, complain, in_decl, + /*integral_constant_expression_p=*/false); + TREE_VEC_ELT (*tp, 3) + = tsubst_expr (TREE_VEC_ELT (it, 3), args, complain, in_decl, + /*integral_constant_expression_p=*/false); + TREE_CHAIN (*tp) = NULL_TREE; + tp = &TREE_CHAIN (*tp); + } + TREE_VEC_ELT (ret, 4) = poplevel (1, 1, 0); + iterator_cache[0] = TREE_PURPOSE (decl); + iterator_cache[1] = ret; + } + return build_tree_list (ret, tsubst_omp_clause_decl (TREE_VALUE (decl), + args, complain, + in_decl, NULL)); + } + /* Handle an OpenMP array section represented as a TREE_LIST (or OMP_CLAUSE_DEPEND_KIND). An OMP_CLAUSE_DEPEND (with a depend kind of OMP_CLAUSE_DEPEND_SINK) can also be represented as a @@ -15960,7 +15998,7 @@ tsubst_omp_clause_decl (tree decl, tree tree length = tsubst_expr (TREE_VALUE (decl), args, complain, in_decl, /*integral_constant_expression_p=*/false); tree chain = tsubst_omp_clause_decl (TREE_CHAIN (decl), args, complain, - in_decl); + in_decl, NULL); if (TREE_PURPOSE (decl) == low_bound && TREE_VALUE (decl) == length && TREE_CHAIN (decl) == chain) @@ -15988,6 +16026,7 @@ tsubst_omp_clauses (tree clauses, enum c { tree new_clauses = NULL_TREE, nc, oc; tree linear_no_step = NULL_TREE; + tree iterator_cache[2] = { NULL_TREE, NULL_TREE }; for (oc = clauses; oc ; oc = OMP_CLAUSE_CHAIN (oc)) { @@ -16022,7 +16061,7 @@ tsubst_omp_clauses (tree clauses, enum c case OMP_CLAUSE_IS_DEVICE_PTR: OMP_CLAUSE_DECL (nc) = tsubst_omp_clause_decl (OMP_CLAUSE_DECL (oc), args, complain, - in_decl); + in_decl, iterator_cache); break; case OMP_CLAUSE_TILE: case OMP_CLAUSE_IF: @@ -16070,13 +16109,13 @@ tsubst_omp_clauses (tree clauses, enum c } OMP_CLAUSE_DECL (nc) = tsubst_omp_clause_decl (OMP_CLAUSE_DECL (oc), args, complain, - in_decl); + in_decl, NULL); break; case OMP_CLAUSE_GANG: case OMP_CLAUSE_ALIGNED: OMP_CLAUSE_DECL (nc) = tsubst_omp_clause_decl (OMP_CLAUSE_DECL (oc), args, complain, - in_decl); + in_decl, NULL); OMP_CLAUSE_OPERAND (nc, 1) = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 1), args, complain, in_decl, /*integral_constant_expression_p=*/false); @@ -16084,7 +16123,7 @@ tsubst_omp_clauses (tree clauses, enum c case OMP_CLAUSE_LINEAR: OMP_CLAUSE_DECL (nc) = tsubst_omp_clause_decl (OMP_CLAUSE_DECL (oc), args, complain, - in_decl); + in_decl, NULL); if (OMP_CLAUSE_LINEAR_STEP (oc) == NULL_TREE) { gcc_assert (!linear_no_step); @@ -16093,7 +16132,7 @@ tsubst_omp_clauses (tree clauses, enum c else if (OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (oc)) OMP_CLAUSE_LINEAR_STEP (nc) = tsubst_omp_clause_decl (OMP_CLAUSE_LINEAR_STEP (oc), args, - complain, in_decl); + complain, in_decl, NULL); else OMP_CLAUSE_LINEAR_STEP (nc) = tsubst_expr (OMP_CLAUSE_LINEAR_STEP (oc), args, complain, --- gcc/testsuite/c-c++-common/gomp/depend-iterator-1.c.jj 2018-06-12 13:02:05.236081056 +0200 +++ gcc/testsuite/c-c++-common/gomp/depend-iterator-1.c 2018-06-12 13:35:30.116318942 +0200 @@ -0,0 +1,75 @@ +int arr[64], arr2[64]; +struct S { int a[4]; } k; +short arr4[4]; +volatile int v; +#define TEST_EQ(x,y) ({ int o[x == y ? 1 : -1]; 0; }) + +void +foo (unsigned char i, signed char j) +{ + #pragma omp task depend (iterator (j=6:2:-2) : out : \ + arr[TEST_EQ (sizeof (j), sizeof (int)), \ + TEST_EQ (sizeof (i), sizeof (unsigned char)), \ + TEST_EQ (sizeof (k), sizeof (struct S)), j], \ + arr2[TEST_EQ (((__typeof (j)) -1) < 0, 1), \ + TEST_EQ (((__typeof (i)) -1) < 0, 0), \ + TEST_EQ (((__typeof (k.a[0])) -1) < 0, 1), j]) \ + depend(out: arr[0]) \ + depend (iterator (long long i=__LONG_LONG_MAX__ - 4:__LONG_LONG_MAX__ - 2:2, \ + unsigned short j=~0U-16:~0U-8:3, \ + short *k=&arr4[1]:&arr4[2]:1) : in : \ + arr[TEST_EQ (sizeof (i), sizeof (long long)), \ + TEST_EQ (sizeof (j), sizeof (unsigned short)), \ + TEST_EQ (sizeof (k), sizeof (short *)), \ + TEST_EQ (sizeof (*k), sizeof (short)), i - __LONG_LONG_MAX__ + 4], \ + arr2[TEST_EQ (((__typeof (i)) -1) < 0, 1), \ + TEST_EQ (((__typeof (j)) -1) < 0, 0), \ + TEST_EQ (((__typeof (*k)) -1) < 0, 1), j - (~0U-16)], \ + arr2[k - &arr4[0]]) \ + depend(in : k) + v++; +} + +void +bar (unsigned char i, signed char j) +{ + int m = j; + int n = j + 2; + #pragma omp task depend (iterator (j=6:2:m) : out : \ + arr[TEST_EQ (sizeof (j), sizeof (int)), \ + TEST_EQ (sizeof (i), sizeof (unsigned char)), \ + TEST_EQ (sizeof (k), sizeof (struct S)), j], \ + arr2[TEST_EQ (((__typeof (j)) -1) < 0, 1), \ + TEST_EQ (((__typeof (i)) -1) < 0, 0), \ + TEST_EQ (((__typeof (k.a[0])) -1) < 0, 1), j]) \ + depend(out: arr[0]) \ + depend (iterator (long long i=__LONG_LONG_MAX__ - 4 - n:__LONG_LONG_MAX__ - 2:2, \ + unsigned short j=~0U-16:~0U-8-n:3, \ + short *k=&arr4[1]:&arr4[n + 2]:1) : in : \ + arr[TEST_EQ (sizeof (i), sizeof (long long)), \ + TEST_EQ (sizeof (j), sizeof (unsigned short)), \ + TEST_EQ (sizeof (k), sizeof (short *)), \ + TEST_EQ (sizeof (*k), sizeof (short)), i - __LONG_LONG_MAX__ + 4], \ + arr2[TEST_EQ (((__typeof (i)) -1) < 0, 1), \ + TEST_EQ (((__typeof (j)) -1) < 0, 0), \ + TEST_EQ (((__typeof (*k)) -1) < 0, 1), j - (~0U-16)], \ + arr2[k - &arr4[0]:10]) \ + depend(in : k) + v++; +} + +void +baz (void) +{ + #pragma omp parallel + #pragma omp master + { + #pragma omp task depend(iterator(unsigned long int k = 0 : 2) : inout : \ + arr[TEST_EQ (sizeof (k), sizeof (unsigned long)), \ + TEST_EQ (((__typeof (k)) -1) < 0, 0), k]) \ + depend(iterator(signed char s = -3 : -12 : -1) : out : \ + arr[TEST_EQ (sizeof (s), sizeof (signed char)), \ + TEST_EQ (((__typeof (s)) -1) < 0, 1), s + 12]) + v++; + } +} --- gcc/testsuite/c-c++-common/gomp/depend-iterator-2.c.jj 2018-06-12 14:29:21.653895079 +0200 +++ gcc/testsuite/c-c++-common/gomp/depend-iterator-2.c 2018-06-13 18:27:33.876741370 +0200 @@ -0,0 +1,91 @@ +int a, b[64]; +struct S { int c; } *d, *e; +struct T; +struct T *f, *g; +int *h; + +void +f1 (void) +{ + #pragma omp task depend (iterator : in : a) /* { dg-error "expected" } */ + ; + #pragma omp task depend (iterator (for = 0 : 2) : in : a) /* { dg-error "expected" } */ + ; + #pragma omp task depend (iterator (5 = 0 : 2) : in : a) /* { dg-error "expected" } */ + ; + #pragma omp task depend (iterator (i : 0 : 2) : in : a) /* { dg-error "expected '='|name a type|expected" } */ + ; + #pragma omp task depend (iterator (i = 0, 1 : 2) : in : a) /* { dg-error "expected" } */ + ; + #pragma omp task depend (iterator (i = (0, 1) : 2) : in : a) + ; + #pragma omp task depend (iterator (i = 0 : 1 : 2 : 3) : in : a) /* { dg-error "expected '.'" } */ + ; + #pragma omp task depend (iterator (i = 0 : 2, 3) : in : a) /* { dg-error "expected" } */ + ; + #pragma omp task depend (iterator (i = 0 : 10 : 2, 3) : in : a) /* { dg-error "expected" } */ + ; + #pragma omp task depend (iterator (i = 0:1), iterator (j = 0:1) : in : a) /* { dg-error "expected ':'|invalid depend kind" } */ + ; + #pragma omp task depend (iterator (i = 0:1): iterator (j = 0:1) : in : a) /* { dg-error "invalid depend kind" } */ + ; + #pragma omp task depend (iterator (i = 0:32) : in : b[i*2:2]) + ; + #pragma omp task depend (iterator (struct S i = 0:1): in : a) /* { dg-error "iterator 'i' has neither integral nor pointer type" } */ + ; + #pragma omp task depend (iterator (void i = 0:1) : in : a) /* { dg-error "iterator 'i' has neither integral nor pointer type" } */ + ; + #pragma omp task depend (iterator (float f = 0.2:0.4) : in : a) /* { dg-error "iterator 'f' has neither integral nor pointer type" } */ + ; + #pragma omp task depend (iterator (struct S *p = d:e:2) : in : a) + ; + #pragma omp task depend (iterator (struct T *p = f:g) : in : a) /* { dg-error "invalid use of" } */ + ; + #pragma omp task depend (iterator (int i = 0:4, \ + struct U { int (*p)[i + 2]; } *p = 0:2) : in : a) /* { dg-error "type of iterator 'p' refers to outer iterator 'i'" "" { target c } } */ + ; /* { dg-error "types may not be defined in iterator type|not an integer constant" "" { target c++ } .-1 } */ + #pragma omp task depend (iterator (i = 0:4, j = i:16) : in : a) /* { dg-error "begin expression refers to outer iterator 'i'" } */ + ; + #pragma omp task depend (iterator (i = 0:4, j = 2:i:1) : in : a) /* { dg-error "end expression refers to outer iterator 'i'" } */ + ; + #pragma omp task depend (iterator (i = 0:4, j = 2:8:i) : in : a) /* { dg-error "step expression refers to outer iterator 'i'" } */ + ; + #pragma omp task depend (iterator (i = *d:2) : in : a) /* { dg-error "aggregate value used where an integer was expected" "" { target c } } */ + ; /* { dg-error "invalid cast from type 'S' to type 'int'" "" { target c++ } .-1 } */ + #pragma omp task depend (iterator (i = 2:*d:2) : in : a) /* { dg-error "aggregate value used where an integer was expected" "" { target c } } */ + ; /* { dg-error "invalid cast from type 'S' to type 'int'" "" { target c++ } .-1 } */ + #pragma omp task depend (iterator (i = 2:4:*d) : in : a) /* { dg-error "aggregate value used where an integer was expected" "" { target c } } */ + ; /* { dg-error "invalid cast from type 'S' to type 'int'" "" { target c++ } .-1 } */ + /* { dg-error "iterator 'i' has zero step" "" { target c } .-2 } */ + #pragma omp task depend (iterator (i = 1.25:2.5:3.5) : in : a) + ; + #pragma omp task depend (iterator (int *p = 23 : h) : in : a) + ; + #pragma omp task depend (iterator (short i=1:3:0) : in : a) /* { dg-error "iterator 'i' has zero step" } */ + ; + #pragma omp task depend (iterator (i = 1 : 3 : 3 - 3) : in : a) /* { dg-error "iterator 'i' has zero step" } */ + ; + #pragma omp task depend (iterator (int *p = &b[6]:&b[9]:4 - 4) : in : a) /* { dg-error "iterator 'p' has zero step" } */ + ; + #pragma omp task depend (iterator (const int i = 0 : 2) : in : a) /* { dg-error "const qualified" } */ + ; + #pragma omp task depend (iterator (const long long unsigned i = 0 : 2) : in : a) /* { dg-error "const qualified" } */ + ; +#if !defined (__cplusplus) && __STDC_VERSION__ >= 201112L + #pragma omp task depend (iterator (_Atomic unsigned i = 0 : 2) : in : a) /* { dg-error "_Atomic" "" { target c } } */ + ; +#endif +} + +void +f2 (void) +{ + int i, j; + #pragma omp for ordered(2) + for (i = 0; i < 64; i++) + for (j = 0; j < 64; j++) + { + #pragma omp ordered depend (iterator (k=0:1) : sink: i - 1, j - 1) /* { dg-error "'iterator' modifier incompatible with 'sink'" } */ + #pragma omp ordered depend (iterator (int l = 0:2:3) : source) /* { dg-error "'iterator' modifier incompatible with 'source'" } */ + } +} --- gcc/testsuite/g++.dg/gomp/depend-iterator-1.C.jj 2018-06-13 18:29:02.828823024 +0200 +++ gcc/testsuite/g++.dg/gomp/depend-iterator-1.C 2018-06-13 18:36:35.959238977 +0200 @@ -0,0 +1,86 @@ +int arr[64], arr2[64]; +struct S { int a[4]; } k; +short arr4[4]; +volatile int v; +#define TEST_EQ(x,y) ({ int o[x == y ? 1 : -1]; 0; }) + +template +void +foo (unsigned char i, signed char j) +{ + #pragma omp task depend (iterator (T j=6:N:-2) : out : \ + arr[TEST_EQ (sizeof (j), sizeof (int)), \ + TEST_EQ (sizeof (i), sizeof (unsigned char)), \ + TEST_EQ (sizeof (k), sizeof (struct S)), j], \ + arr2[TEST_EQ (((__typeof (j)) -1) < 0, 1), \ + TEST_EQ (((__typeof (i)) -1) < 0, 0), \ + TEST_EQ (((__typeof (k.a[0])) -1) < 0, 1), j]) \ + depend(out: arr[0]) \ + depend (iterator (U i=__LONG_LONG_MAX__ - 4:__LONG_LONG_MAX__ - N:N, \ + V j=~0U-16:~0U-8:3, \ + W *k=&arr4[1]:&arr4[2]:1) : in : \ + arr[TEST_EQ (sizeof (i), sizeof (long long)), \ + TEST_EQ (sizeof (j), sizeof (unsigned short)), \ + TEST_EQ (sizeof (k), sizeof (short *)), \ + TEST_EQ (sizeof (*k), sizeof (short)), i - __LONG_LONG_MAX__ + 4], \ + arr2[TEST_EQ (((__typeof (i)) -1) < 0, 1), \ + TEST_EQ (((__typeof (j)) -1) < 0, 0), \ + TEST_EQ (((__typeof (*k)) -1) < 0, 1), j - (~0U-16)], \ + arr2[k - &arr4[0]]) \ + depend(in : k) + v++; +} + +template +void +bar (unsigned char i, signed char j) +{ + int m = j; + int n = j + 2; + #pragma omp task depend (iterator (j=N:2:m) : out : \ + arr[TEST_EQ (sizeof (j), sizeof (int)), \ + TEST_EQ (sizeof (i), sizeof (unsigned char)), \ + TEST_EQ (sizeof (k), sizeof (struct S)), j], \ + arr2[TEST_EQ (((__typeof (j)) -1) < 0, 1), \ + TEST_EQ (((__typeof (i)) -1) < 0, 0), \ + TEST_EQ (((__typeof (k.a[0])) -1) < 0, 1), j]) \ + depend(out: arr[0]) \ + depend (iterator (U i=__LONG_LONG_MAX__ - 4 - n:__LONG_LONG_MAX__ - 2:2, \ + unsigned short j=~0U-16:~0U-8-n:3, \ + W k=&arr4[N-5]:&arr4[n + 2]:1) : in : \ + arr[TEST_EQ (sizeof (i), sizeof (long long)), \ + TEST_EQ (sizeof (j), sizeof (unsigned short)), \ + TEST_EQ (sizeof (k), sizeof (short *)), \ + TEST_EQ (sizeof (*k), sizeof (short)), i - __LONG_LONG_MAX__ + 4], \ + arr2[TEST_EQ (((__typeof (i)) -1) < 0, 1), \ + TEST_EQ (((__typeof (j)) -1) < 0, 0), \ + TEST_EQ (((__typeof (*k)) -1) < 0, 1), j - (~0U-16)], \ + arr2[k - &arr4[0]:10]) \ + depend(in : k) + v++; +} + +template +void +baz (void) +{ + #pragma omp parallel + #pragma omp master + { + #pragma omp task depend(iterator(T k = N : 2) : inout : \ + arr[TEST_EQ (sizeof (k), sizeof (unsigned long)), \ + TEST_EQ (((__typeof (k)) -1) < N, 0), k]) \ + depend(iterator(U s = -3 : -12 : -1 + N) : out : \ + arr[TEST_EQ (sizeof (s), sizeof (signed char)), \ + TEST_EQ (((__typeof (s)) -1) < 0, 1), s + 12]) + v++; + } +} + +void +test (void) +{ + foo (0, 0); + bar (0, -2); + baz (); +} --- gcc/testsuite/g++.dg/gomp/depend-iterator-2.C.jj 2018-06-13 18:59:57.212537261 +0200 +++ gcc/testsuite/g++.dg/gomp/depend-iterator-2.C 2018-06-13 19:15:06.993378812 +0200 @@ -0,0 +1,110 @@ +int a, b[64]; +struct S { int c; } *d, *e; +struct T; +struct T *f, *g; +int *h; + +template +void +f1 () +{ + #pragma omp task depend (iterator : in : a) // { dg-error "expected" } + ; + #pragma omp task depend (iterator (for = 0 : 2) : in : a) // { dg-error "expected" } + ; + #pragma omp task depend (iterator (5 = 0 : 2) : in : a) // { dg-error "expected" } + ; + #pragma omp task depend (iterator (i : N : 2) : in : a) // { dg-error "expected '='|name a type|expected" } + ; + #pragma omp task depend (iterator (i = 0, 1 : 2) : in : a) // { dg-error "expected" } + ; + #pragma omp task depend (iterator (i = (0, 1) : 2) : in : a) + ; + #pragma omp task depend (iterator (i = 0 : 1 : 2 : 3) : in : a) // { dg-error "expected '.'" } + ; + #pragma omp task depend (iterator (i = 0 : 2, 3) : in : a) // { dg-error "expected" } + ; + #pragma omp task depend (iterator (i = N : 10 : 2, 3) : in : a) // { dg-error "expected" } + ; + #pragma omp task depend (iterator (i = 0:1), iterator (j = 0:1) : in : a) // { dg-error "expected ':'|invalid depend kind" } + ; + #pragma omp task depend (iterator (i = 0:1): iterator (j = 0:1) : in : a) // { dg-error "invalid depend kind" } + ; + #pragma omp task depend (iterator (i = N:32) : in : b[i*2:2]) + ; + #pragma omp task depend (iterator (void i = 0:1) : in : a) // { dg-error "iterator 'i' has neither integral nor pointer type" } + ; + #pragma omp task depend (iterator (U *p = d:e:2) : in : a) + ; + #pragma omp task depend (iterator (W i = N:4, \ + struct U2 { W *p; } *p = 0:2) : in : a) // { dg-error "types may not be defined in iterator type" } + ; + #pragma omp task depend (iterator (i = 0:4, j = i:16) : in : a) // { dg-error "begin expression refers to outer iterator 'i'" } + ; + #pragma omp task depend (iterator (i = N:4, j = 2:i:1) : in : a) // { dg-error "end expression refers to outer iterator 'i'" } + ; + #pragma omp task depend (iterator (i = 0:4, j = 2:8:i) : in : a) // { dg-error "step expression refers to outer iterator 'i'" } + ; + #pragma omp task depend (iterator (i = 1.25:2.5:3.5) : in : a) + ; + #pragma omp task depend (iterator (W *p = 23 : h) : in : a) + ; + #pragma omp task depend (iterator (const int i = N : 2) : in : a) // { dg-error "const qualified" } + ; + #pragma omp task depend (iterator (const long long unsigned i = 0 : 2) : in : a) // { dg-error "const qualified" } + ; +} + +template +void +f2 () +{ + int i, j; + #pragma omp for ordered(2) + for (i = 0; i < 64; i++) + for (j = 0; j < 64; j++) + { + #pragma omp ordered depend (iterator (k=0:N) : sink: i - 1, j - 1) // { dg-error "'iterator' modifier incompatible with 'sink'" } + #pragma omp ordered depend (iterator (W l = 0:2:3) : source) // { dg-error "'iterator' modifier incompatible with 'source'" } + } +} + +template +void +f3 () +{ + #pragma omp task depend (iterator (U i = 0:1): in : a) // { dg-error "iterator 'i' has neither integral nor pointer type" } + ; + #pragma omp task depend (iterator (V f = 0.2:0.4) : in : a) // { dg-error "iterator 'f' has neither integral nor pointer type" } + ; + #pragma omp task depend (iterator (struct T *p = f:g) : in : a) // { dg-error "invalid use of" } + ; + #pragma omp task depend (iterator (i = *d:2) : in : a) // { dg-error "invalid cast from type 'S' to type 'int'" } + ; + #pragma omp task depend (iterator (i = 2:*d:2) : in : a) // { dg-error "invalid cast from type 'S' to type 'int'" } + ; + #pragma omp task depend (iterator (i = 2:4:*d) : in : a) // { dg-error "invalid cast from type 'S' to type 'int'" } + ; + #pragma omp task depend (iterator (i = 1.25:2.5:3.5) : in : a) + ; + #pragma omp task depend (iterator (W *p = 23 : h) : in : a) + ; + #pragma omp task depend (iterator (short i=1:3:N) : in : a) // { dg-error "iterator 'i' has zero step" } + ; + #pragma omp task depend (iterator (i = 1 : 3 : N + 3 - 3) : in : a) // { dg-error "iterator 'i' has zero step" } + ; + #pragma omp task depend (iterator (int *p = &b[6]:&b[9]:4 - 4) : in : a) // { dg-error "iterator 'p' has zero step" } + ; + #pragma omp task depend (iterator (X i = N : 2) : in : a) // { dg-error "const qualified" } + ; + #pragma omp task depend (iterator (Y i = 0 : 2) : in : a) // { dg-error "const qualified" } + ; +} + +void +f4 () +{ + f1 (); + f2 (); + f3 (); +} --- libgomp/testsuite/libgomp.c-c++-common/depend-iterator-1.c.jj 2018-06-12 11:41:35.817715556 +0200 +++ libgomp/testsuite/libgomp.c-c++-common/depend-iterator-1.c 2018-06-12 14:39:09.759522148 +0200 @@ -0,0 +1,81 @@ +#ifdef __cplusplus +extern "C" +#endif +void abort (void); +int arr[64], arr2[64], arr3[64]; + +int * +foo (int x, int y, long z) +{ + int v; + switch (x) + { + case 1: + if (z != 0 || y < 0 || y >= 64) + abort (); + #pragma omp atomic capture + { + v = arr2[y]; + arr2[y]++; + } + if (v != 0) abort (); + return &arr[y]; + case 2: + if (y < 0 || y > 60 || (y & 3) || z < 0 || z >= 4) + abort (); + #pragma omp atomic + arr2[y + z] = arr2[y + z] + 2; + return &arr[y + z]; + case 3: + if (z < 0 || z > 60 || (z & 3) || y < 0 || y >= 4) + abort (); + #pragma omp atomic + arr2[y + z] = arr2[y + z] + 4; + return &arr[y + z]; + case 4: + if (y != 0 || z > 64 || z <= 0) + abort (); + #pragma omp atomic + arr2[z - 1] = arr2[z - 1] + 8; + return &arr[z - 1]; + default: + abort (); + } +} + +volatile int beg, end, step; + +int +main () +{ + int m; + beg = 60; + end = -4; + step = -4; + #pragma omp parallel + #pragma omp master + { + int i; + for (i = 0; i < 64; i++) + #pragma omp task depend (iterator (j=i:i+1) : out : foo (1, j, 0)[0]) + arr[i] = i; + #pragma omp task depend (iterator (int k=beg:end:step,long int l=0:4:1) : inout : \ + foo (2, k, l)[0], foo (3, l, k)[0]) private (i) + for (i = 0; i < 64; i++) + if (arr[i] != i) + abort (); + else + arr[i] = arr[i] + 1; + #pragma omp task depend (iterator (int *p=&arr3[64]:&arr3[0]:-1) : in : \ + foo (4, 0, p - &arr3[0])[0]) depend (in : beg) + for (i = 0; i < 64; i++) + if (arr[i] != i + 1) + abort (); + else + arr[i] = arr[i] + 2; + } + for (m = 0; m < 64; m++) + if (arr[m] != m + 3 || arr2[m] != 15) + abort (); + return 0; +} --- libgomp/testsuite/libgomp.c++/depend-iterator-1.C.jj 2018-06-13 17:56:36.206038796 +0200 +++ libgomp/testsuite/libgomp.c++/depend-iterator-1.C 2018-06-13 18:07:09.183618914 +0200 @@ -0,0 +1,119 @@ +extern "C" void abort (); +int arr[64], arr2[64], arr3[64]; + +int * +foo (int x, int y, long z) +{ + int v; + switch (x) + { + case 1: + if (z != 0 || y < 0 || y >= 64) + abort (); + #pragma omp atomic capture + { + v = arr2[y]; + arr2[y]++; + } + if (v != 0) abort (); + return &arr[y]; + case 2: + if (y < 0 || y > 60 || (y & 3) || z < 0 || z >= 4) + abort (); + #pragma omp atomic + arr2[y + z] = arr2[y + z] + 2; + return &arr[y + z]; + case 3: + if (z < 0 || z > 60 || (z & 3) || y < 0 || y >= 4) + abort (); + #pragma omp atomic + arr2[y + z] = arr2[y + z] + 4; + return &arr[y + z]; + case 4: + if (y != 0 || z > 64 || z <= 0) + abort (); + #pragma omp atomic + arr2[z - 1] = arr2[z - 1] + 8; + return &arr[z - 1]; + default: + abort (); + } +} + +volatile int beg, end, step; + +template +void +bar () +{ + #pragma omp parallel + #pragma omp master + { + int i; + for (i = 0; i < 64; i++) + #pragma omp task depend (iterator (j=i:i+1) : out : foo (1, j, 0)[0]) + arr[i] = i; + #pragma omp task depend (iterator (int k=beg:end:step,long int l=0:4:1) : inout : \ + foo (2, k, l)[0], foo (3, l, k)[0]) private (i) + for (i = 0; i < 64; i++) + if (arr[i] != i) + abort (); + else + arr[i] = arr[i] + 1; + #pragma omp task depend (iterator (int *p=&arr3[64]:&arr3[0]:-1) : in : \ + foo (4, 0, p - &arr3[0])[0]) depend (in : beg) + for (i = 0; i < 64; i++) + if (arr[i] != i + 1) + abort (); + else + arr[i] = arr[i] + 2; + } +} + +template +void +baz (A beg, A end, A step) +{ + #pragma omp parallel + #pragma omp master + { + int i; + for (i = 0; i < 64; i++) + #pragma omp task depend (iterator (A j=i:i+1) : out : foo (1, j, 0)[0]) + arr[i] = i; + #pragma omp task depend (iterator (A k=beg:end:step,B l=0:4:1) : inout : \ + foo (2, k, l)[0], foo (3, l, k)[0]) private (i) + for (i = 0; i < 64; i++) + if (arr[i] != i) + abort (); + else + arr[i] = arr[i] + 1; + #pragma omp task depend (iterator (C p=&arr3[64]:&arr3[0]:-1) : in : \ + foo (4, 0, p - &arr3[0])[0]) depend (in : beg) + for (i = 0; i < 64; i++) + if (arr[i] != i + 1) + abort (); + else + arr[i] = arr[i] + 2; + } +} + +int +main () +{ + int m; + beg = 60; + end = -4; + step = -4; + bar<0> (); + for (m = 0; m < 64; m++) + if (arr[m] != m + 3 || arr2[m] != 15) + abort (); + else + arr[m] = arr2[m] = 0; + baz (beg, end, step); + for (m = 0; m < 64; m++) + if (arr[m] != m + 3 || arr2[m] != 15) + abort (); + return 0; +}