From patchwork Tue Sep 5 19:28:22 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1830095 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (ip-8-43-85-97.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4RgFtr11Blz1yg7 for ; Wed, 6 Sep 2023 05:29:24 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 6CDB1385E002 for ; Tue, 5 Sep 2023 19:29:21 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from esa3.mentor.iphmx.com (esa3.mentor.iphmx.com [68.232.137.180]) by sourceware.org (Postfix) with ESMTPS id 4BDCF385842C; Tue, 5 Sep 2023 19:29:04 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 4BDCF385842C Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mentor.com X-IronPort-AV: E=Sophos;i="6.02,229,1688457600"; d="scan'208";a="16179080" Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa3.mentor.iphmx.com with ESMTP; 05 Sep 2023 11:28:58 -0800 IronPort-SDR: OP+9LNLGh5d7oJS0Uvx5VT1RbHIe2iBfoRSdSDYi1dTWbFKeBRjRNa9r3g5Ek9FXnwGoaaWoKk uuqkwlvIl6tl4poTzPA+a/o5LfyiBWNdK5pjPLA1O1JSCoQ7yfBpzV0XK06SYBqP82KFQv0vpX DCKjdB13JptxyKbzmCimniqz+TE9zTAZIiIidbKdSkuTGnBOmX7QH2GMKhtNVNS+FlRFe4s2Mm Iok40y8WlXn+zfJqeR00BI35pRodDuL2skEXJIv3v3RJs/5oiMeyI58WobwpBv0nJFeB0qEBHB DEA= From: Julian Brown To: CC: , , Subject: [PATCH 2/8] OpenMP: lvalue parsing for map/to/from clauses (C) Date: Tue, 5 Sep 2023 12:28:22 -0700 Message-ID: <78fa6c4dae60578a8feffe204bfe24d85d19520c.1693941293.git.julian@codesourcery.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: References: MIME-Version: 1.0 X-Originating-IP: [137.202.0.90] X-ClientProxiedBy: svr-ies-mbx-12.mgc.mentorg.com (139.181.222.12) To svr-ies-mbx-11.mgc.mentorg.com (139.181.222.11) X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, KAM_SHORT, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" This patch adds support for parsing general lvalues ("locator list item types") for OpenMP "map", "to" and "from" clauses to the C front-end, similar to the previously-posted patch for C++. Such syntax is permitted for OpenMP 5.0 and above. It was previously posted for mainline here: https://gcc.gnu.org/pipermail/gcc-patches/2022-December/609038.html and for the og13 branch here: https://gcc.gnu.org/pipermail/gcc-patches/2023-June/623355.html 2023-09-05 Julian Brown gcc/c/ * c-pretty-print.cc (c_pretty_printer::postfix_expression, c_pretty_printer::expression): Add OMP_ARRAY_SECTION support. * c-parser.cc (c_parser_braced_init, c_parser_conditional_expression): Don't allow OpenMP array section. (c_parser_postfix_expression): Don't allow array section in statement expression. (c_parser_postfix_expression_after_primary): Add support for OpenMP array section parsing. (c_parser_expr_list): Don't allow OpenMP array section here. (c_parser_omp_variable_list): Change ALLOW_DEREF parameter to MAP_LVALUE. Support parsing of general lvalues in "map", "to" and "from" clauses. (c_parser_omp_var_list_parens): Change ALLOW_DEREF parameter to MAP_LVALUE. Update call to c_parser_omp_variable_list. (c_parser_oacc_data_clause): Update calls to c_parser_omp_var_list_parens. (c_parser_omp_clause_reduction): Use OMP_ARRAY_SECTION tree node instead of TREE_LIST for array sections. (c_parser_omp_target): Allow GOMP_MAP_ATTACH. * c-tree.h (c_omp_array_section_p): Add extern declaration. (build_omp_array_section): Add prototype. * c-typeck.c (c_omp_array_section_p): Add flag. (mark_exp_read): Support OMP_ARRAY_SECTION. (build_omp_array_section): Add function. (build_external_ref): Tweak error path for OpenMP array sections. (handle_omp_array_sections_1): Use OMP_ARRAY_SECTION tree code instead of TREE_LIST. Handle more kinds of expressions. (c_oacc_check_attachments): Use OMP_ARRAY_SECTION instead of TREE_LIST for array sections. (c_finish_omp_clauses): Use OMP_ARRAY_SECTION instead of TREE_LIST. Check for supported expression types. gcc/testsuite/ * gcc.dg/gomp/bad-array-section-c-1.c: New test. * gcc.dg/gomp/bad-array-section-c-2.c: New test. * gcc.dg/gomp/bad-array-section-c-3.c: New test. * gcc.dg/gomp/bad-array-section-c-4.c: New test. * gcc.dg/gomp/bad-array-section-c-5.c: New test. * gcc.dg/gomp/bad-array-section-c-6.c: New test. * gcc.dg/gomp/bad-array-section-c-7.c: New test. * gcc.dg/gomp/bad-array-section-c-8.c: New test. libgomp/ * testsuite/libgomp.c-c++-common/ind-base-4.c: New test. * testsuite/libgomp.c-c++-common/unary-ptr-1.c: New test. --- gcc/c-family/c-pretty-print.cc | 12 ++ gcc/c/c-parser.cc | 181 +++++++++++++++--- gcc/c/c-tree.h | 2 + gcc/c/c-typeck.cc | 109 +++++++++-- .../gcc.dg/gomp/bad-array-section-c-1.c | 16 ++ .../gcc.dg/gomp/bad-array-section-c-2.c | 13 ++ .../gcc.dg/gomp/bad-array-section-c-3.c | 24 +++ .../gcc.dg/gomp/bad-array-section-c-4.c | 26 +++ .../gcc.dg/gomp/bad-array-section-c-5.c | 15 ++ .../gcc.dg/gomp/bad-array-section-c-6.c | 16 ++ .../gcc.dg/gomp/bad-array-section-c-7.c | 26 +++ .../gcc.dg/gomp/bad-array-section-c-8.c | 21 ++ .../libgomp.c-c++-common/ind-base-4.c | 50 +++++ .../libgomp.c-c++-common/unary-ptr-1.c | 16 ++ 14 files changed, 482 insertions(+), 45 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/gomp/bad-array-section-c-1.c create mode 100644 gcc/testsuite/gcc.dg/gomp/bad-array-section-c-2.c create mode 100644 gcc/testsuite/gcc.dg/gomp/bad-array-section-c-3.c create mode 100644 gcc/testsuite/gcc.dg/gomp/bad-array-section-c-4.c create mode 100644 gcc/testsuite/gcc.dg/gomp/bad-array-section-c-5.c create mode 100644 gcc/testsuite/gcc.dg/gomp/bad-array-section-c-6.c create mode 100644 gcc/testsuite/gcc.dg/gomp/bad-array-section-c-7.c create mode 100644 gcc/testsuite/gcc.dg/gomp/bad-array-section-c-8.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/ind-base-4.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/unary-ptr-1.c diff --git a/gcc/c-family/c-pretty-print.cc b/gcc/c-family/c-pretty-print.cc index 7536a7c471ff..225ac7ef2851 100644 --- a/gcc/c-family/c-pretty-print.cc +++ b/gcc/c-family/c-pretty-print.cc @@ -1615,6 +1615,17 @@ c_pretty_printer::postfix_expression (tree e) pp_c_right_bracket (this); break; + case OMP_ARRAY_SECTION: + postfix_expression (TREE_OPERAND (e, 0)); + pp_c_left_bracket (this); + if (TREE_OPERAND (e, 1)) + expression (TREE_OPERAND (e, 1)); + pp_colon (this); + if (TREE_OPERAND (e, 2)) + expression (TREE_OPERAND (e, 2)); + pp_c_right_bracket (this); + break; + case CALL_EXPR: { call_expr_arg_iterator iter; @@ -2664,6 +2675,7 @@ c_pretty_printer::expression (tree e) case POSTINCREMENT_EXPR: case POSTDECREMENT_EXPR: case ARRAY_REF: + case OMP_ARRAY_SECTION: case CALL_EXPR: case COMPONENT_REF: case BIT_FIELD_REF: diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index ae3a25737151..36215096af4c 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -5767,6 +5767,8 @@ c_parser_braced_init (c_parser *parser, tree type, bool nested_p, location_t brace_loc = c_parser_peek_token (parser)->location; gcc_obstack_init (&braced_init_obstack); gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE)); + bool save_c_omp_array_section_p = c_omp_array_section_p; + c_omp_array_section_p = false; matching_braces braces; braces.consume_open (parser); if (nested_p) @@ -5805,6 +5807,7 @@ c_parser_braced_init (c_parser *parser, tree type, bool nested_p, break; } } + c_omp_array_section_p = save_c_omp_array_section_p; c_token *next_tok = c_parser_peek_token (parser); if (next_tok->type != CPP_CLOSE_BRACE) { @@ -8194,6 +8197,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after, { struct c_expr cond, exp1, exp2, ret; location_t start, cond_loc, colon_loc; + bool save_c_omp_array_section_p = c_omp_array_section_p; gcc_assert (!after || c_dialect_objc ()); @@ -8201,6 +8205,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after, if (c_parser_next_token_is_not (parser, CPP_QUERY)) return cond; + c_omp_array_section_p = false; if (cond.value != error_mark_node) start = cond.get_start (); else @@ -8253,6 +8258,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after, ret.set_error (); ret.original_code = ERROR_MARK; ret.original_type = NULL; + c_omp_array_section_p = save_c_omp_array_section_p; return ret; } { @@ -8299,6 +8305,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after, } set_c_expr_source_range (&ret, start, exp2.get_finish ()); ret.m_decimal = 0; + c_omp_array_section_p = save_c_omp_array_section_p; return ret; } @@ -9750,6 +9757,7 @@ c_parser_postfix_expression (c_parser *parser) /* A statement expression. */ tree stmt; location_t brace_loc; + bool save_c_omp_array_section_p = c_omp_array_section_p; c_parser_consume_token (parser); brace_loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); @@ -9766,6 +9774,7 @@ c_parser_postfix_expression (c_parser *parser) expr.set_error (); break; } + c_omp_array_section_p = false; stmt = c_begin_stmt_expr (); c_parser_compound_statement_nostart (parser); location_t close_loc = c_parser_peek_token (parser)->location; @@ -9776,6 +9785,7 @@ c_parser_postfix_expression (c_parser *parser) expr.value = c_finish_stmt_expr (brace_loc, stmt); set_c_expr_source_range (&expr, loc, close_loc); mark_exp_read (expr.value); + c_omp_array_section_p = save_c_omp_array_section_p; } else { @@ -11234,7 +11244,7 @@ c_parser_postfix_expression_after_primary (c_parser *parser, struct c_expr expr) { struct c_expr orig_expr; - tree ident, idx; + tree ident, idx, len; location_t sizeof_arg_loc[3], comp_loc; tree sizeof_arg[3]; unsigned int literal_zero_mask; @@ -11253,16 +11263,41 @@ c_parser_postfix_expression_after_primary (c_parser *parser, case CPP_OPEN_SQUARE: /* Array reference. */ c_parser_consume_token (parser); - idx = c_parser_expression (parser).value; - c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, - "expected %<]%>"); - start = expr.get_start (); - finish = parser->tokens_buf[0].location; - expr.value = build_array_ref (op_loc, expr.value, idx); - set_c_expr_source_range (&expr, start, finish); - expr.original_code = ERROR_MARK; - expr.original_type = NULL; - expr.m_decimal = 0; + idx = len = NULL_TREE; + if (!c_omp_array_section_p + || c_parser_next_token_is_not (parser, CPP_COLON)) + idx = c_parser_expression (parser).value; + + if (c_omp_array_section_p + && c_parser_next_token_is (parser, CPP_COLON)) + { + c_parser_consume_token (parser); + if (c_parser_next_token_is_not (parser, CPP_CLOSE_SQUARE)) + len = c_parser_expression (parser).value; + + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, + "expected %<]%>"); + + start = expr.get_start (); + finish = parser->tokens_buf[0].location; + expr.value = build_omp_array_section (op_loc, expr.value, idx, + len); + set_c_expr_source_range (&expr, start, finish); + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + } + else + { + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, + "expected %<]%>"); + start = expr.get_start (); + finish = parser->tokens_buf[0].location; + expr.value = build_array_ref (op_loc, expr.value, idx); + set_c_expr_source_range (&expr, start, finish); + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + expr.m_decimal = 0; + } break; case CPP_OPEN_PAREN: /* Function call. */ @@ -11545,6 +11580,8 @@ c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p, vec *orig_types; struct c_expr expr; unsigned int idx = 0; + bool save_c_omp_array_section_p = c_omp_array_section_p; + c_omp_array_section_p = false; ret = make_tree_vector (); if (p_orig_types == NULL) @@ -11598,6 +11635,7 @@ c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p, } if (orig_types) *p_orig_types = orig_types; + c_omp_array_section_p = save_c_omp_array_section_p; return ret; } @@ -13825,7 +13863,7 @@ static tree c_parser_omp_variable_list (c_parser *parser, location_t clause_loc, enum omp_clause_code kind, tree list, - bool allow_deref = false) + bool map_lvalue = false) { auto_vec dims; bool array_section_p; @@ -13835,6 +13873,8 @@ c_parser_omp_variable_list (c_parser *parser, while (1) { + tree t = NULL_TREE; + if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) { if (c_parser_next_token_is_not (parser, CPP_NAME) @@ -13915,8 +13955,97 @@ c_parser_omp_variable_list (c_parser *parser, parser->tokens = tokens.address (); parser->tokens_avail = tokens.length (); } + else if (map_lvalue + && (kind == OMP_CLAUSE_MAP + || kind == OMP_CLAUSE_TO + || kind == OMP_CLAUSE_FROM)) + { + location_t loc = c_parser_peek_token (parser)->location; + bool save_c_omp_array_section_p = c_omp_array_section_p; + c_omp_array_section_p = true; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + if (expr.value != error_mark_node) + mark_exp_read (expr.value); + c_omp_array_section_p = save_c_omp_array_section_p; + tree decl = expr.value; - tree t = NULL_TREE; + /* This code rewrites a parsed expression containing various tree + codes used to represent array accesses into a more uniform nest of + OMP_ARRAY_SECTION nodes before it is processed by + c-typeck.cc:handle_omp_array_sections_1. It might be more + efficient to move this logic to that function instead, analysing + the parsed expression directly rather than this preprocessed + form. (See also equivalent code in cp/parser.cc, + cp/semantics.cc). */ + dims.truncate (0); + if (TREE_CODE (decl) == OMP_ARRAY_SECTION) + { + while (TREE_CODE (decl) == OMP_ARRAY_SECTION) + { + tree low_bound = TREE_OPERAND (decl, 1); + tree length = TREE_OPERAND (decl, 2); + dims.safe_push (omp_dim (low_bound, length, loc, false)); + decl = TREE_OPERAND (decl, 0); + } + + while (TREE_CODE (decl) == ARRAY_REF + || TREE_CODE (decl) == INDIRECT_REF + || TREE_CODE (decl) == COMPOUND_EXPR) + { + if (TREE_CODE (decl) == COMPOUND_EXPR) + { + decl = TREE_OPERAND (decl, 1); + STRIP_NOPS (decl); + } + else if (TREE_CODE (decl) == INDIRECT_REF) + { + dims.safe_push (omp_dim (integer_zero_node, + integer_one_node, loc, true)); + decl = TREE_OPERAND (decl, 0); + } + else /* ARRAY_REF. */ + { + tree index = TREE_OPERAND (decl, 1); + dims.safe_push (omp_dim (index, integer_one_node, loc, + true)); + decl = TREE_OPERAND (decl, 0); + } + } + + for (int i = dims.length () - 1; i >= 0; i--) + decl = build_omp_array_section (loc, decl, dims[i].low_bound, + dims[i].length); + } + else if (TREE_CODE (decl) == INDIRECT_REF) + { + /* Turn *foo into the representation previously used for + foo[0]. */ + decl = TREE_OPERAND (decl, 0); + STRIP_NOPS (decl); + + decl = build_omp_array_section (loc, decl, integer_zero_node, + integer_one_node); + } + else if (TREE_CODE (decl) == ARRAY_REF) + { + tree idx = TREE_OPERAND (decl, 1); + + decl = TREE_OPERAND (decl, 0); + STRIP_NOPS (decl); + + decl = build_omp_array_section (loc, decl, idx, integer_one_node); + } + else if (TREE_CODE (decl) == NON_LVALUE_EXPR + || CONVERT_EXPR_P (decl)) + decl = TREE_OPERAND (decl, 0); + + tree u = build_omp_clause (clause_loc, kind); + OMP_CLAUSE_DECL (u) = decl; + OMP_CLAUSE_CHAIN (u) = list; + list = u; + + goto next_item; + } if (c_parser_next_token_is (parser, CPP_NAME) && c_parser_peek_token (parser)->id_kind == C_ID_ID) @@ -13967,8 +14096,7 @@ c_parser_omp_variable_list (c_parser *parser, case OMP_CLAUSE_TO: start_component_ref: while (c_parser_next_token_is (parser, CPP_DOT) - || (allow_deref - && c_parser_next_token_is (parser, CPP_DEREF))) + || c_parser_next_token_is (parser, CPP_DEREF)) { location_t op_loc = c_parser_peek_token (parser)->location; location_t arrow_loc = UNKNOWN_LOCATION; @@ -14069,9 +14197,7 @@ c_parser_omp_variable_list (c_parser *parser, || kind == OMP_CLAUSE_TO) && !array_section_p && (c_parser_next_token_is (parser, CPP_DOT) - || (allow_deref - && c_parser_next_token_is (parser, - CPP_DEREF)))) + || c_parser_next_token_is (parser, CPP_DEREF))) { for (unsigned i = 0; i < dims.length (); i++) { @@ -14083,7 +14209,9 @@ c_parser_omp_variable_list (c_parser *parser, } else for (unsigned i = 0; i < dims.length (); i++) - t = tree_cons (dims[i].low_bound, dims[i].length, t); + t = build_omp_array_section (clause_loc, t, + dims[i].low_bound, + dims[i].length); } if ((kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) @@ -14131,6 +14259,8 @@ c_parser_omp_variable_list (c_parser *parser, parser->tokens = &parser->tokens_buf[0]; parser->tokens_avail = tokens_avail; } + + next_item: if (c_parser_next_token_is_not (parser, CPP_COMMA)) break; @@ -14147,7 +14277,7 @@ c_parser_omp_variable_list (c_parser *parser, static tree c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind, - tree list, bool allow_deref = false) + tree list, bool map_lvalue = false) { /* The clauses location. */ location_t loc = c_parser_peek_token (parser)->location; @@ -14155,7 +14285,7 @@ c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind, matching_parens parens; if (parens.require_open (parser)) { - list = c_parser_omp_variable_list (parser, loc, kind, list, allow_deref); + list = c_parser_omp_variable_list (parser, loc, kind, list, map_lvalue); parens.skip_until_found_close (parser); } return list; @@ -14224,7 +14354,7 @@ c_parser_oacc_data_clause (c_parser *parser, pragma_omp_clause c_kind, gcc_unreachable (); } tree nl, c; - nl = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_MAP, list, true); + nl = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_MAP, list, false); for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) OMP_CLAUSE_SET_MAP_KIND (c, kind); @@ -15814,13 +15944,15 @@ c_parser_omp_clause_reduction (c_parser *parser, enum omp_clause_code kind, for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) { tree d = OMP_CLAUSE_DECL (c), type; - if (TREE_CODE (d) != TREE_LIST) + if (TREE_CODE (d) != OMP_ARRAY_SECTION) type = TREE_TYPE (d); else { int cnt = 0; tree t; - for (t = d; TREE_CODE (t) == TREE_LIST; t = TREE_CHAIN (t)) + for (t = d; + TREE_CODE (t) == OMP_ARRAY_SECTION; + t = TREE_OPERAND (t, 0)) cnt++; type = TREE_TYPE (t); while (cnt > 0) @@ -22479,6 +22611,7 @@ check_clauses: case GOMP_MAP_FIRSTPRIVATE_POINTER: case GOMP_MAP_ALWAYS_POINTER: case GOMP_MAP_ATTACH_DETACH: + case GOMP_MAP_ATTACH: break; default: error_at (OMP_CLAUSE_LOCATION (*pc), diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 7c5234e80fd9..5cd507563695 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -726,6 +726,7 @@ extern int in_alignof; extern int in_sizeof; extern int in_typeof; extern bool c_in_omp_for; +extern bool c_omp_array_section_p; extern tree c_last_sizeof_arg; extern location_t c_last_sizeof_loc; @@ -764,6 +765,7 @@ extern tree composite_type (tree, tree); extern tree build_component_ref (location_t, tree, tree, location_t, location_t); extern tree build_array_ref (location_t, tree, tree); +extern tree build_omp_array_section (location_t, tree, tree, tree); extern tree build_external_ref (location_t, tree, bool, tree *); extern void pop_maybe_used (bool); extern struct c_expr c_expr_sizeof_expr (location_t, struct c_expr); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 597b77181dc2..b399341084d2 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -76,6 +76,9 @@ int in_typeof; /* True when parsing OpenMP loop expressions. */ bool c_in_omp_for; +/* True when parsing OpenMP map clause. */ +bool c_omp_array_section_p; + /* The argument of last parsed sizeof expression, only to be tested if expr.original_code == SIZEOF_EXPR. */ tree c_last_sizeof_arg; @@ -2001,6 +2004,13 @@ mark_exp_read (tree exp) case C_MAYBE_CONST_EXPR: mark_exp_read (TREE_OPERAND (exp, 1)); break; + case OMP_ARRAY_SECTION: + mark_exp_read (TREE_OPERAND (exp, 0)); + if (TREE_OPERAND (exp, 1)) + mark_exp_read (TREE_OPERAND (exp, 1)); + if (TREE_OPERAND (exp, 2)) + mark_exp_read (TREE_OPERAND (exp, 2)); + break; default: break; } @@ -2878,6 +2888,53 @@ build_array_ref (location_t loc, tree array, tree index) return ret; } } + +/* Build an OpenMP array section reference, creating an exact type for the + resulting expression based on the element type and bounds if possible. If + we have variable bounds, create an incomplete array type for the result + instead. */ + +tree +build_omp_array_section (location_t loc, tree array, tree index, tree length) +{ + tree idxtype; + + if (index != NULL_TREE + && length != NULL_TREE + && INTEGRAL_TYPE_P (TREE_TYPE (index)) + && INTEGRAL_TYPE_P (TREE_TYPE (length))) + { + tree low = fold_convert (sizetype, index); + tree high = fold_convert (sizetype, length); + high = size_binop (PLUS_EXPR, low, high); + high = size_binop (MINUS_EXPR, high, size_one_node); + idxtype = build_range_type (sizetype, low, high); + } + else if ((index == NULL_TREE || integer_zerop (index)) + && length != NULL_TREE + && INTEGRAL_TYPE_P (TREE_TYPE (length))) + idxtype = build_index_type (length); + else + idxtype = NULL_TREE; + + tree type = TREE_TYPE (array); + gcc_assert (type); + + tree sectype, eltype = TREE_TYPE (type); + + /* It's not an array or pointer type. Just reuse the type of the original + expression as the type of the array section (an error will be raised + anyway, later). */ + if (eltype == NULL_TREE + || error_operand_p (eltype) + || error_operand_p (idxtype)) + sectype = TREE_TYPE (array); + else + sectype = build_array_type (eltype, idxtype); + + return build3_loc (loc, OMP_ARRAY_SECTION, sectype, array, index, length); +} + /* Build an external reference to identifier ID. FUN indicates whether this will be used for a function call. LOC is the source @@ -2917,7 +2974,11 @@ build_external_ref (location_t loc, tree id, bool fun, tree *type) return error_mark_node; } - if (TREE_TYPE (ref) == error_mark_node) + /* For an OpenMP map clause, we can get better diagnostics for decls with + unmappable types if we return the decl with an error_mark_node type, + rather than returning error_mark_node for the decl itself. */ + if (TREE_TYPE (ref) == error_mark_node + && !c_omp_array_section_p) return error_mark_node; if (TREE_UNAVAILABLE (ref)) @@ -13635,7 +13696,7 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, { tree ret, low_bound, length, type; bool openacc = (ort & C_ORT_ACC) != 0; - if (TREE_CODE (t) != TREE_LIST) + if (TREE_CODE (t) != OMP_ARRAY_SECTION) { if (error_operand_p (t)) return error_mark_node; @@ -13660,7 +13721,9 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, t = ai.unconverted_ref_origin (); if (t == error_mark_node) return error_mark_node; - if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + if (!VAR_P (t) + && (ort == C_ORT_ACC || !EXPR_P (t)) + && TREE_CODE (t) != PARM_DECL) { if (DECL_P (t)) error_at (OMP_CLAUSE_LOCATION (c), @@ -13708,14 +13771,14 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, return ret; } - ret = handle_omp_array_sections_1 (c, TREE_CHAIN (t), types, + ret = handle_omp_array_sections_1 (c, TREE_OPERAND (t, 0), types, maybe_zero_len, first_non_one, ort); if (ret == error_mark_node || ret == NULL_TREE) return ret; type = TREE_TYPE (ret); - low_bound = TREE_PURPOSE (t); - length = TREE_VALUE (t); + low_bound = TREE_OPERAND (t, 1); + length = TREE_OPERAND (t, 2); if (low_bound == error_mark_node || length == error_mark_node) return error_mark_node; @@ -13908,7 +13971,7 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, tree lb = save_expr (low_bound); if (lb != low_bound) { - TREE_PURPOSE (t) = lb; + TREE_OPERAND (t, 1) = lb; low_bound = lb; } } @@ -13939,14 +14002,15 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, array-section-subscript, the array section could be non-contiguous. */ if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_AFFINITY - && TREE_CODE (TREE_CHAIN (t)) == TREE_LIST) + && TREE_CODE (TREE_OPERAND (t, 0)) == OMP_ARRAY_SECTION) { /* If any prior dimension has a non-one length, then deem this array section as non-contiguous. */ - for (tree d = TREE_CHAIN (t); TREE_CODE (d) == TREE_LIST; - d = TREE_CHAIN (d)) + for (tree d = TREE_OPERAND (t, 0); + TREE_CODE (d) == OMP_ARRAY_SECTION; + d = TREE_OPERAND (d, 0)) { - tree d_length = TREE_VALUE (d); + tree d_length = TREE_OPERAND (d, 2); if (d_length == NULL_TREE || !integer_onep (d_length)) { error_at (OMP_CLAUSE_LOCATION (c), @@ -13969,7 +14033,7 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, tree lb = save_expr (low_bound); if (lb != low_bound) { - TREE_PURPOSE (t) = lb; + TREE_OPERAND (t, 1) = lb; low_bound = lb; } ret = build_array_ref (OMP_CLAUSE_LOCATION (c), ret, low_bound); @@ -14032,10 +14096,10 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) maybe_zero_len = true; for (i = num, t = OMP_CLAUSE_DECL (c); i > 0; - t = TREE_CHAIN (t)) + t = TREE_OPERAND (t, 0)) { - tree low_bound = TREE_PURPOSE (t); - tree length = TREE_VALUE (t); + tree low_bound = TREE_OPERAND (t, 1); + tree length = TREE_OPERAND (t, 2); i--; if (low_bound @@ -14441,8 +14505,8 @@ c_oacc_check_attachments (tree c) { tree t = OMP_CLAUSE_DECL (c); - while (TREE_CODE (t) == TREE_LIST) - t = TREE_CHAIN (t); + while (TREE_CODE (t) == OMP_ARRAY_SECTION) + t = TREE_OPERAND (t, 0); if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE) { @@ -14550,7 +14614,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) case OMP_CLAUSE_TASK_REDUCTION: need_implicitly_determined = true; t = OMP_CLAUSE_DECL (c); - if (TREE_CODE (t) == TREE_LIST) + if (TREE_CODE (t) == OMP_ARRAY_SECTION) { if (handle_omp_array_sections (c, ort)) { @@ -15171,7 +15235,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) } else last_iterators = NULL_TREE; - if (TREE_CODE (t) == TREE_LIST) + if (TREE_CODE (t) == OMP_ARRAY_SECTION) { if (handle_omp_array_sections (c, ort)) remove = true; @@ -15281,7 +15345,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) auto_vec addr_tokens; t = OMP_CLAUSE_DECL (c); - if (TREE_CODE (t) == TREE_LIST) + if (TREE_CODE (t) == OMP_ARRAY_SECTION) { grp_start_p = pc; grp_sentinel = OMP_CLAUSE_CHAIN (c); @@ -15449,6 +15513,9 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) { + if (ort != C_ORT_ACC && EXPR_P (t)) + break; + error_at (OMP_CLAUSE_LOCATION (c), "%qE is not a variable in %qs clause", t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); @@ -15677,7 +15744,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) case OMP_CLAUSE_HAS_DEVICE_ADDR: t = OMP_CLAUSE_DECL (c); - if (TREE_CODE (t) == TREE_LIST) + if (TREE_CODE (t) == OMP_ARRAY_SECTION) { if (handle_omp_array_sections (c, ort)) remove = true; diff --git a/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-1.c b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-1.c new file mode 100644 index 000000000000..a2226ebf6429 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-1.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ + +int foo (int *ptr); + +int main() +{ + int arr[20]; + /* Reject array section as function argument. */ +#pragma omp target map(foo(arr[3:5])) +/* { dg-error {expected '\]' before ':' token} "" { target *-*-* } .-1 } */ +/* { dg-warning {passing argument 1 of 'foo' makes pointer from integer without a cast} "" { target *-*-* } .-2 } */ +/* { dg-message {sorry, unimplemented: unsupported map expression} "" { target *-*-* } .-3 } */ + { } + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-2.c b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-2.c new file mode 100644 index 000000000000..449487ad55d6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-2.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ + +int main() +{ + int arr[20]; + /* Reject array section in statement expression. */ +#pragma omp target map( ({ int x = 5; arr[0:x]; }) ) +/* { dg-error {expected '\]' before ':' token} "" { target *-*-* } .-1 } */ +/* { dg-message {sorry, unimplemented: unsupported map expression} "" { target *-*-* } .-2 } */ + { } + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-3.c b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-3.c new file mode 100644 index 000000000000..8be15ced8c06 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-3.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ + +struct S { + int *ptr; +}; + +int main() +{ + int arr[20]; + + /* Reject array section in compound initialiser. */ +#pragma omp target map( (struct S) { .ptr = (int *) arr[5:5] } ) +/* { dg-error {expected '\]' before ':' token} "" { target *-*-* } .-1 } */ +/* { dg-warning {cast to pointer from integer of different size} "" { target *-*-* } .-2 } */ +/* { dg-message {sorry, unimplemented: unsupported map expression} "" { target *-*-* } .-3 } */ + { } + + /* ...and this is unsupported too (probably not useful anyway). */ +#pragma omp target map( (struct S) { .ptr = &arr[5] } ) +/* { dg-message {sorry, unimplemented: unsupported map expression} "" { target *-*-* } .-1 } */ + { } + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-4.c b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-4.c new file mode 100644 index 000000000000..b78cdfc8a13e --- /dev/null +++ b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-4.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ + +int x; + +int main() +{ + int arr[20]; + int *ptr; + /* "arr[1:10]" looks like it might be an expression of array type, hence + able to be indexed (again). This isn't allowed, though. */ +#pragma omp target map(arr[1:10][2]) +/* { dg-error {'arr\[1\]' does not have pointer or array type} "" { target *-*-* } .-1 } */ + { } +#pragma omp target map(arr[1:x][2]) +/* { dg-error {'arr\[1\]' does not have pointer or array type} "" { target *-*-* } .-1 } */ + { } + /* ...and nor is this. */ +#pragma omp target map(ptr[1:10][2]) +/* { dg-error {'\*\(ptr \+ [0-9]+\)' does not have pointer or array type} "" { target *-*-* } .-1 } */ + { } +#pragma omp target map(ptr[1:x][2]) +/* { dg-error {'\*\(ptr \+ [0-9]+\)' does not have pointer or array type} "" { target *-*-* } .-1 } */ + { } + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-5.c b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-5.c new file mode 100644 index 000000000000..ae343464a19a --- /dev/null +++ b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-5.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ + +int partly = 0; + +int main() +{ + int arr[20]; +#pragma omp target map(partly ? arr[5:5] : arr) +/* { dg-error {expected '\]' before ':' token} "" { target *-*-* } .-1 } */ +/* { dg-warning {pointer/integer type mismatch in conditional expression} "" { target *-*-* } .-2 } */ +/* { dg-message {sorry, unimplemented: unsupported map expression} "" { target *-*-* } .-3 } */ + { } + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-6.c b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-6.c new file mode 100644 index 000000000000..bfca4f0fca3f --- /dev/null +++ b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-6.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ + +int x; + +int main() +{ + int arr[20]; +#pragma omp target map(arr[5:5] * 2) +/* { dg-error {invalid operands to binary \*} "" { target *-*-* } .-1 } */ + { } +#pragma omp target map(arr[x:5] * 2) +/* { dg-error {invalid operands to binary \*} "" { target *-*-* } .-1 } */ + { } + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-7.c b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-7.c new file mode 100644 index 000000000000..1fd9e2b383a4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-7.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ + +int x; + +struct T { + int arr[20]; +}; + +struct S { + struct T *tvec; +}; + +int main() +{ + struct S *s; + /* You can't use an array section like this. Make sure sensible errors are + reported. */ +#pragma omp target map(s->tvec[3:5].arr[0:20]) +/* { dg-error {'\(struct T \*\)&s->tvec\[3:5\]' is a pointer; did you mean to use '->'\?} "" { target *-*-* } .-1 } */ + { } +#pragma omp target map(s->tvec[5:x].arr[0:20]) +/* { dg-error {'\(struct T \*\)&s->tvec\[5:x\]' is a pointer; did you mean to use '->'\?} "" { target *-*-* } .-1 } */ + { } + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-8.c b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-8.c new file mode 100644 index 000000000000..f90eca1fa9fa --- /dev/null +++ b/gcc/testsuite/gcc.dg/gomp/bad-array-section-c-8.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ + +int x; + +int main() +{ + int arr1[40]; + int arr2[40]; +#pragma omp target map(arr1[arr2[4:5]:arr2[6:7]]) +/* { dg-error {low bound 'arr2\[4:5\]' of array section does not have integral type} "" { target *-*-* } .-1 } */ + { } +#pragma omp target map(arr1[arr2[:1]:arr2[6:1]]) +/* { dg-error {low bound 'arr2\[:1\]' of array section does not have integral type} "" { target *-*-* } .-1 } */ + { } +#pragma omp target map(arr1[x:arr2[6:1]]) +/* { dg-error {length 'arr2\[6:1\]' of array section does not have integral type} "" { target *-*-* } .-1 } */ + { } + + return 0; +} + diff --git a/libgomp/testsuite/libgomp.c-c++-common/ind-base-4.c b/libgomp/testsuite/libgomp.c-c++-common/ind-base-4.c new file mode 100644 index 000000000000..91549ac4d245 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/ind-base-4.c @@ -0,0 +1,50 @@ +// { dg-do run } +// { dg-options "-fopenmp" } + +#include +#include + +typedef struct +{ + int x[10]; +} S; + +typedef struct +{ + S ***s; +} T; + +typedef struct +{ + T **t; +} U; + +void +foo (void) +{ + U *u = (U *) malloc (sizeof (U)); + T *real_t = (T *) malloc (sizeof (T)); + S *real_s = (S *) malloc (sizeof (S)); + T **t_pp = &real_t; + S **s_pp = &real_s; + S ***s_ppp = &s_pp; + u->t = t_pp; + (*u->t)->s = s_ppp; + for (int i = 0; i < 10; i++) + (**((*u->t)->s))->x[i] = 0; +#pragma omp target map(u->t, *u->t, (*u->t)->s, *(*u->t)->s, **(*u->t)->s, \ + (**(*u->t)->s)->x[0:10]) + for (int i = 0; i < 10; i++) + (**((*u->t)->s))->x[i] = i * 3; + for (int i = 0; i < 10; i++) + assert ((**((*u->t)->s))->x[i] == i * 3); + free (real_s); + free (real_t); + free (u); +} + +int main (int argc, char *argv[]) +{ + foo (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/unary-ptr-1.c b/libgomp/testsuite/libgomp.c-c++-common/unary-ptr-1.c new file mode 100644 index 000000000000..3623b2695763 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/unary-ptr-1.c @@ -0,0 +1,16 @@ +#include + +int main (int argc, char *argv[]) +{ + int y = 0; + int *x = &y; + +#pragma omp target map(*x) + { + (*x)++; + } + + assert (y == 1); + + return 0; +}