From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from esa1.mentor.iphmx.com (esa1.mentor.iphmx.com [68.232.129.153]) by sourceware.org (Postfix) with ESMTPS id 517EC3898C72; Fri, 18 Mar 2022 16:27:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 517EC3898C72 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="5.90,192,1643702400"; d="scan'208";a="75920205" Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa1.mentor.iphmx.com with ESMTP; 18 Mar 2022 08:27:02 -0800 IronPort-SDR: +lfj+CX8YNoOulnFhBtGtVf/lBasHALxRJh0U1h8IF17A9AkXXJe+15kLC1+BCcPVf8VfvhAvj Sa2YAVIOWrLPHq8ztnKctizf56KmMyqvu0jraCZFwH/pSpvva8F9l9RrdJ5NuP/+cKtasyHl5s 4K0WZg+hcb0PfRuqKvNe1lDx9MSsUOXU/cO5i4UWbvo8omOxKd1n57jPK2dyLM7bUvRsuuy/Mv aYZxH0ys8JcFh1tlUiwQx7rQsSn9T1gsBjAzLl6/iNwCfTjM6LS9JxuvUTHMohuyoPIWEcIFxW idQ= From: Julian Brown To: CC: Jakub Jelinek , Thomas Schwinge , Tobias Burnus , Fortran List Subject: [PATCH v2 06/11] OpenMP: lvalue parsing for map clauses (C++) Date: Fri, 18 Mar 2022 09:26:47 -0700 Message-ID: <62e4e371468638d2f155c528a5c1e597558a56ac.1647619144.git.julian@codesourcery.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain X-Originating-IP: [137.202.0.90] X-ClientProxiedBy: svr-ies-mbx-09.mgc.mentorg.com (139.181.222.9) To SVR-IES-MBX-04.mgc.mentorg.com (139.181.222.4) X-Spam-Status: No, score=-11.3 required=5.0 tests=BAYES_00, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, SCC_5_SHORT_WORD_LINES, SPF_HELO_PASS, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: fortran@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Fortran mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 18 Mar 2022 16:27:09 -0000 This patch changes parsing for OpenMP map clauses in C++ to use the generic expression parser, hence adds support for parsing general lvalues (as required by OpenMP 5.0+). So far only a few new types of expression are actually supported throughout compilation (including everything in the testsuite of course, and newly-added tests), and we attempt to reject unsupported expressions in order to avoid surprises for the user. This version of the patch adds code to recalculate the bias for ATTACH operations on struct bases which are not DECL_P (edit: oops, and leaves in a commented-out line). 2022-03-17 Julian Brown gcc/c-family/ * c-omp.cc (c_omp_address_inspector::map_supported_p): Support OMP_ARRAY_SECTION. gcc/cp/ * error.cc (dump_expr): Handle OMP_ARRAY_SECTION. * parser.cc (cp_parser_new): Initialize parser->omp_array_section_p. (cp_parser_postfix_open_square_expression): Support OMP_ARRAY_SECTION parsing. (cp_parser_omp_var_list_no_open): Remove ALLOW_DEREF parameter, add MAP_LVALUE in its place. Supported generalised lvalue parsing for map clauses. (cp_parser_omp_var_list): Remove ALLOW_DEREF parameter, add MAP_LVALUE. Pass to cp_parser_omp_var_list_no_open. (cp_parser_oacc_data_clause, cp_parser_omp_all_clauses): Update calls to cp_parser_omp_var_list. * parser.h (cp_parser): Add omp_array_section_p field. * semantics.cc (handle_omp_array_sections_1): Handle more types of map expression. (handle_omp_array_section): Disallow pointer-to-member mappings. (finish_omp_clauses): Check for supported types of expression. gcc/ * gimplify.cc (omp_containing_struct): Handle POINTER_PLUS_EXPR. (accumulate_sibling_list): Fix support for non-DECL_P struct bases. Don't create firstprivate pointers for struct bases that are explicitly mapped TO elsewhere in the clause list. Add support for adjusting struct ATTACH bias. (omp_ptrmem_p): New function. (omp_build_struct_sibling_lists): Support length-two group for synthesized inner struct mapping. Explicitly disallow pointers to members. Recalculate bias for struct ATTACH nodes. * tree-pretty-print.c (dump_generic_node): Support OMP_ARRAY_SECTION. * tree.def (OMP_ARRAY_SECTION): New tree code. gcc/testsuite/ * c-c++-common/gomp/map-6.c: Update expected output. * g++.dg/gomp/pr67522.C: Likewise. * g++.dg/gomp/ind-base-3.C: New test. * g++.dg/gomp/map-assignment-1.C: New test. * g++.dg/gomp/map-inc-1.C: New test. * g++.dg/gomp/map-lvalue-ref-1.C: New test. * g++.dg/gomp/map-ptrmem-1.C: New test. * g++.dg/gomp/map-ptrmem-2.C: New test. * g++.dg/gomp/map-static-cast-lvalue-1.C: New test. * g++.dg/gomp/map-ternary-1.C: New test. * g++.dg/gomp/member-array-2.C: New test. libgomp/ * testsuite/libgomp.c++/ind-base-1.C: New test. * testsuite/libgomp.c++/ind-base-2.C: New test. * testsuite/libgomp.c++/map-comma-1.C: New test. * testsuite/libgomp.c++/map-rvalue-ref-1.C: New test. * testsuite/libgomp.c++/struct-ref-1.C: New test. * testsuite/libgomp.c-c++-common/array-field-1.c: New test. * testsuite/libgomp.c-c++-common/array-of-struct-1.c: New test. * testsuite/libgomp.c-c++-common/array-of-struct-2.c: New test. --- gcc/c-family/c-omp.cc | 1 + gcc/cp/error.cc | 9 + gcc/cp/parser.cc | 141 +++++++++++++-- gcc/cp/parser.h | 3 + gcc/cp/semantics.cc | 59 ++++++- gcc/gimplify.cc | 119 +++++++++++-- gcc/testsuite/c-c++-common/gomp/map-6.c | 4 +- gcc/testsuite/g++.dg/gomp/ind-base-3.C | 38 ++++ gcc/testsuite/g++.dg/gomp/map-assignment-1.C | 12 ++ gcc/testsuite/g++.dg/gomp/map-inc-1.C | 10 ++ gcc/testsuite/g++.dg/gomp/map-lvalue-ref-1.C | 19 ++ gcc/testsuite/g++.dg/gomp/map-ptrmem-1.C | 37 ++++ gcc/testsuite/g++.dg/gomp/map-ptrmem-2.C | 40 +++++ .../g++.dg/gomp/map-static-cast-lvalue-1.C | 17 ++ gcc/testsuite/g++.dg/gomp/map-ternary-1.C | 20 +++ gcc/testsuite/g++.dg/gomp/member-array-2.C | 92 ++++++++++ gcc/testsuite/g++.dg/gomp/pr67522.C | 2 +- gcc/tree-pretty-print.cc | 14 ++ gcc/tree.def | 3 + libgomp/testsuite/libgomp.c++/ind-base-1.C | 162 ++++++++++++++++++ libgomp/testsuite/libgomp.c++/ind-base-2.C | 49 ++++++ libgomp/testsuite/libgomp.c++/map-comma-1.C | 15 ++ .../testsuite/libgomp.c++/map-rvalue-ref-1.C | 22 +++ libgomp/testsuite/libgomp.c++/struct-ref-1.C | 97 +++++++++++ .../libgomp.c-c++-common/array-field-1.c | 35 ++++ .../libgomp.c-c++-common/array-of-struct-1.c | 65 +++++++ .../libgomp.c-c++-common/array-of-struct-2.c | 65 +++++++ 27 files changed, 1123 insertions(+), 27 deletions(-) create mode 100644 gcc/testsuite/g++.dg/gomp/ind-base-3.C create mode 100644 gcc/testsuite/g++.dg/gomp/map-assignment-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/map-inc-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/map-lvalue-ref-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/map-ptrmem-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/map-ptrmem-2.C create mode 100644 gcc/testsuite/g++.dg/gomp/map-static-cast-lvalue-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/map-ternary-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/member-array-2.C create mode 100644 libgomp/testsuite/libgomp.c++/ind-base-1.C create mode 100644 libgomp/testsuite/libgomp.c++/ind-base-2.C create mode 100644 libgomp/testsuite/libgomp.c++/map-comma-1.C create mode 100644 libgomp/testsuite/libgomp.c++/map-rvalue-ref-1.C create mode 100644 libgomp/testsuite/libgomp.c++/struct-ref-1.C create mode 100644 libgomp/testsuite/libgomp.c-c++-common/array-field-1.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/array-of-struct-1.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/array-of-struct-2.c diff --git a/gcc/c-family/c-omp.cc b/gcc/c-family/c-omp.cc index 3907afe0418..421ccdddd76 100644 --- a/gcc/c-family/c-omp.cc +++ b/gcc/c-family/c-omp.cc @@ -3232,6 +3232,7 @@ c_omp_address_inspector::map_supported_p () || TREE_CODE (t) == SAVE_EXPR || TREE_CODE (t) == POINTER_PLUS_EXPR || TREE_CODE (t) == NON_LVALUE_EXPR + || TREE_CODE (t) == OMP_ARRAY_SECTION || TREE_CODE (t) == NOP_EXPR) if (TREE_CODE (t) == COMPOUND_EXPR) t = TREE_OPERAND (t, 1); diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc index e76842e1a2a..a2693aadcd0 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -2436,6 +2436,15 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags) pp_cxx_right_bracket (pp); break; + case OMP_ARRAY_SECTION: + dump_expr (pp, TREE_OPERAND (t, 0), flags); + pp_cxx_left_bracket (pp); + dump_expr (pp, TREE_OPERAND (t, 1), flags); + pp_colon (pp); + dump_expr (pp, TREE_OPERAND (t, 2), flags); + pp_cxx_right_bracket (pp); + break; + case UNARY_PLUS_EXPR: dump_unary_op (pp, "+", t, flags); break; diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 94a5c64be4c..efb65543e11 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -4266,6 +4266,9 @@ cp_parser_new (cp_lexer *lexer) parser->omp_declare_simd = NULL; parser->oacc_routine = NULL; + /* Allow array slice in expression. */ + parser->omp_array_section_p = false; + /* Not declaring an implicit function template. */ parser->auto_is_implicit_function_template_parm_p = false; parser->fully_implicit_function_template_p = false; @@ -8021,6 +8024,7 @@ cp_parser_postfix_open_square_expression (cp_parser *parser, releasing_vec expression_list = NULL; location_t loc = cp_lexer_peek_token (parser->lexer)->location; bool saved_greater_than_is_operator_p; + bool saved_colon_corrects_to_scope_p; /* Consume the `[' token. */ cp_lexer_consume_token (parser->lexer); @@ -8028,6 +8032,9 @@ cp_parser_postfix_open_square_expression (cp_parser *parser, saved_greater_than_is_operator_p = parser->greater_than_is_operator_p; parser->greater_than_is_operator_p = true; + saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p; + parser->colon_corrects_to_scope_p = false; + /* Parse the index expression. */ /* ??? For offsetof, there is a question of what to allow here. If offsetof is not being used in an integral constant expression context, @@ -8038,7 +8045,8 @@ cp_parser_postfix_open_square_expression (cp_parser *parser, constant expressions here. */ if (for_offsetof) index = cp_parser_constant_expression (parser); - else + else if (!parser->omp_array_section_p + || cp_lexer_next_token_is_not (parser->lexer, CPP_COLON)) { if (cxx_dialect >= cxx23 && cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SQUARE)) @@ -8097,6 +8105,32 @@ cp_parser_postfix_open_square_expression (cp_parser *parser, parser->greater_than_is_operator_p = saved_greater_than_is_operator_p; + if (parser->omp_array_section_p + && cp_lexer_next_token_is (parser->lexer, CPP_COLON)) + { + cp_lexer_consume_token (parser->lexer); + tree length = NULL_TREE; + if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_SQUARE)) + length = cp_parser_expression (parser); + + parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; + + if ((index && error_operand_p (index)) + || (length && error_operand_p (length))) + return error_mark_node; + + cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE); + + /* NOTE: We are reusing using the type of the whole array as the type of + the array section here, which isn't necessarily entirely correct. + Might need revisiting. */ + return build3_loc (input_location, OMP_ARRAY_SECTION, + TREE_TYPE (postfix_expression), + postfix_expression, index, length); + } + + parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; + /* Look for the closing `]'. */ cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE); @@ -36536,7 +36570,7 @@ struct omp_dim static tree cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, tree list, bool *colon, - bool allow_deref = false) + bool map_lvalue = false) { auto_vec dims; bool array_section_p; @@ -36547,12 +36581,95 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, parser->colon_corrects_to_scope_p = false; *colon = false; } + begin_scope (sk_omp, NULL); while (1) { tree name, decl; if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) cp_parser_parse_tentatively (parser); + else if (map_lvalue && kind == OMP_CLAUSE_MAP) + { + auto s = make_temp_override (parser->omp_array_section_p, true); + token = cp_lexer_peek_token (parser->lexer); + location_t loc = token->location; + decl = cp_parser_assignment_expression (parser); + + 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 (REFERENCE_REF_P (decl)) + break; + + 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); + } + } + + /* Bare references have their own special handling, so remove + the explicit dereference added by convert_from_reference. */ + if (REFERENCE_REF_P (decl)) + decl = TREE_OPERAND (decl, 0); + + for (int i = dims.length () - 1; i >= 0; i--) + decl = tree_cons (dims[i].low_bound, dims[i].length, decl); + } + else if (TREE_CODE (decl) == INDIRECT_REF) + { + bool ref_p = REFERENCE_REF_P (decl); + + /* Turn *foo into the representation previously used for + foo[0]. */ + decl = TREE_OPERAND (decl, 0); + STRIP_NOPS (decl); + + /* ...but don't add the [0:1] representation for references + (because they have special handling elsewhere). */ + if (!ref_p) + decl = tree_cons (integer_zero_node, integer_one_node, decl); + } + else if (TREE_CODE (decl) == ARRAY_REF) + { + tree idx = TREE_OPERAND (decl, 1); + + decl = TREE_OPERAND (decl, 0); + STRIP_NOPS (decl); + + decl = tree_cons (idx, integer_one_node, decl); + } + else if (TREE_CODE (decl) == NON_LVALUE_EXPR + || CONVERT_EXPR_P (decl)) + decl = TREE_OPERAND (decl, 0); + + goto build_clause; + } token = cp_lexer_peek_token (parser->lexer); if (kind != 0 && cp_parser_is_keyword (token, RID_THIS)) @@ -36622,8 +36739,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, case OMP_CLAUSE_TO: start_component_ref: while (cp_lexer_next_token_is (parser->lexer, CPP_DOT) - || (allow_deref - && cp_lexer_next_token_is (parser->lexer, CPP_DEREF))) + || cp_lexer_next_token_is (parser->lexer, CPP_DEREF)) { cpp_ttype ttype = cp_lexer_next_token_is (parser->lexer, CPP_DOT) @@ -36709,9 +36825,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, || kind == OMP_CLAUSE_TO) && !array_section_p && (cp_lexer_next_token_is (parser->lexer, CPP_DOT) - || (allow_deref - && cp_lexer_next_token_is (parser->lexer, - CPP_DEREF)))) + || cp_lexer_next_token_is (parser->lexer, CPP_DEREF))) { for (unsigned i = 0; i < dims.length (); i++) { @@ -36745,6 +36859,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, cp_parser_parse_definitely (parser); } + build_clause: tree u = build_omp_clause (token->location, kind); OMP_CLAUSE_DECL (u) = decl; OMP_CLAUSE_CHAIN (u) = list; @@ -36766,6 +36881,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, { *colon = true; cp_parser_require (parser, CPP_COLON, RT_COLON); + finish_scope (); return list; } @@ -36786,6 +36902,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, goto get_comma; } + finish_scope (); return list; } @@ -36794,11 +36911,11 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, static tree cp_parser_omp_var_list (cp_parser *parser, enum omp_clause_code kind, tree list, - bool allow_deref = false) + bool map_lvalue = false) { if (cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) return cp_parser_omp_var_list_no_open (parser, kind, list, NULL, - allow_deref); + map_lvalue); return list; } @@ -36865,7 +36982,7 @@ cp_parser_oacc_data_clause (cp_parser *parser, pragma_omp_clause c_kind, gcc_unreachable (); } tree nl, c; - nl = cp_parser_omp_var_list (parser, OMP_CLAUSE_MAP, list, true); + nl = cp_parser_omp_var_list (parser, OMP_CLAUSE_MAP, list, false); for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) OMP_CLAUSE_SET_MAP_KIND (c, kind); @@ -40227,12 +40344,12 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, clauses); else clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_TO, clauses, - true); + false); c_name = "to"; break; case PRAGMA_OMP_CLAUSE_FROM: clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FROM, clauses, - true); + false); c_name = "from"; break; case PRAGMA_OMP_CLAUSE_UNIFORM: diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index d688fd18fd5..7ae507bb135 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -404,6 +404,9 @@ struct GTY(()) cp_parser { /* TRUE if omp::directive or omp::sequence attributes may not appear. */ bool omp_attrs_forbidden_p; + /* TRUE if an OpenMP array section is allowed. */ + bool omp_array_section_p; + /* Tracks the function's template parameter list when declaring a function using generic type parameters. This is either a new chain in the case of a fully implicit function template or an extension of the function's existing diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 81e2788f43a..931af062c87 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -5123,7 +5123,9 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, ret = t_refto; if (TREE_CODE (t) == FIELD_DECL) ret = finish_non_static_data_member (t, NULL_TREE, NULL_TREE); - else if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + else if (!VAR_P (t) + && (ort == C_ORT_ACC || !EXPR_P (t)) + && TREE_CODE (t) != PARM_DECL) { if (processing_template_decl && TREE_CODE (t) != OVERLOAD) return NULL_TREE; @@ -5667,6 +5669,32 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) return false; + if (TREE_CODE (first) == INDIRECT_REF) + { + /* Detect and skip adding extra nodes for pointer-to-member + mappings. These are unsupported for now. */ + tree tmp = TREE_OPERAND (first, 0); + + if (TREE_CODE (tmp) == NON_LVALUE_EXPR) + tmp = TREE_OPERAND (tmp, 0); + + if (TREE_CODE (tmp) == INDIRECT_REF) + tmp = TREE_OPERAND (tmp, 0); + + if (TREE_CODE (tmp) == POINTER_PLUS_EXPR) + { + tree offset = TREE_OPERAND (tmp, 1); + STRIP_NOPS (offset); + if (TYPE_PTRMEM_P (TREE_TYPE (offset))) + { + sorry_at (OMP_CLAUSE_LOCATION (c), + "pointer-to-member mapping %qE not supported", + OMP_CLAUSE_DECL (c)); + return true; + } + } + } + cp_omp_address_inspector t_insp (OMP_CLAUSE_LOCATION (c), t); if (t_insp.maybe_zero_length_array_section (c)) @@ -7929,6 +7957,15 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) cp_omp_address_inspector t_insp (OMP_CLAUSE_LOCATION (c), t); + if (!t_insp.map_supported_p ()) + { + sorry_at (OMP_CLAUSE_LOCATION (c), + "unsupported map expression %qE", + OMP_CLAUSE_DECL (c)); + remove = true; + break; + } + if (t_insp.component_access_p () && !t_insp.get_base_pointer ()) { @@ -7939,6 +7976,15 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) if (!DECL_P (rt)) break; + if (!t_insp.map_supported_p ()) + { + sorry_at (OMP_CLAUSE_LOCATION (c), + "unsupported map expression %qE", + OMP_CLAUSE_DECL (c)); + remove = true; + break; + } + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP && OMP_CLAUSE_MAP_IMPLICIT (c) && (bitmap_bit_p (&map_head, DECL_UID (rt)) @@ -8023,6 +8069,14 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) OMP_CLAUSE_DECL (c) = t_refto; if (type_dependent_expression_p (t_refto)) break; + if (!t_insp.map_supported_p ()) + { + sorry_at (OMP_CLAUSE_LOCATION (c), + "unsupported map expression %qE", + OMP_CLAUSE_DECL (c)); + remove = true; + break; + } if (t == error_mark_node) { remove = true; @@ -8052,7 +8106,8 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ALWAYS_POINTER - || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH)) + || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH + || (ort != C_ORT_ACC && EXPR_P (t)))) break; if (DECL_P (t)) error_at (OMP_CLAUSE_LOCATION (c), diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc index 0b8c221e4c8..4ad3c4fad58 100644 --- a/gcc/gimplify.cc +++ b/gcc/gimplify.cc @@ -9241,7 +9241,8 @@ omp_containing_struct (tree expr) || TREE_CODE (TREE_OPERAND (expr, 0)) == INDIRECT_REF || (TREE_CODE (TREE_OPERAND (expr, 0)) == MEM_REF && integer_zerop (TREE_OPERAND (TREE_OPERAND (expr, 0), 1))) - || TREE_CODE (TREE_OPERAND (expr, 0)) == ARRAY_REF) + || TREE_CODE (TREE_OPERAND (expr, 0)) == ARRAY_REF + || TREE_CODE (TREE_OPERAND (expr, 0)) == POINTER_PLUS_EXPR) expr = TREE_OPERAND (expr, 0); else internal_error ("unhandled component"); @@ -9785,7 +9786,10 @@ move_concat_nodes_after (tree first_new, tree *last_new_tail, tree *first_ptr, static tree * accumulate_sibling_list (enum omp_region_type region_type, enum tree_code code, hash_map - *&struct_map_to_clause, tree *grp_start_p, + *&struct_map_to_clause, + hash_map + *group_map, + tree *grp_start_p, tree grp_end, tree *inner) { poly_offset_int coffset; @@ -9928,8 +9932,7 @@ accumulate_sibling_list (enum omp_region_type region_type, enum tree_code code, while (TREE_CODE (sdecl) == POINTER_PLUS_EXPR) sdecl = TREE_OPERAND (sdecl, 0); - if (DECL_P (sdecl) - && POINTER_TYPE_P (TREE_TYPE (sdecl)) + if (POINTER_TYPE_P (TREE_TYPE (sdecl)) && (region_type & ORT_TARGET)) { tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (grp_end), @@ -9943,8 +9946,21 @@ accumulate_sibling_list (enum omp_region_type region_type, enum tree_code code, && (TREE_CODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (base, 0), 0))) == REFERENCE_TYPE)))); - enum gomp_map_kind mkind = base_ref ? GOMP_MAP_FIRSTPRIVATE_REFERENCE - : GOMP_MAP_FIRSTPRIVATE_POINTER; + enum gomp_map_kind mkind; + bool mapped_to_p = false; + omp_mapping_group **decl_group_p = group_map->get (sdecl); + if (decl_group_p) + { + tree grp_first = *(*decl_group_p)->grp_start; + enum gomp_map_kind first_kind = OMP_CLAUSE_MAP_KIND (grp_first); + if (*decl_group_p && GOMP_MAP_COPY_TO_P (first_kind)) + mapped_to_p = true; + } + if (DECL_P (sdecl) && !mapped_to_p) + mkind = base_ref ? GOMP_MAP_FIRSTPRIVATE_REFERENCE + : GOMP_MAP_FIRSTPRIVATE_POINTER; + else + mkind = GOMP_MAP_ATTACH; OMP_CLAUSE_SET_MAP_KIND (c2, mkind); OMP_CLAUSE_DECL (c2) = sdecl; tree baddr = build_fold_addr_expr (base); @@ -9960,7 +9976,10 @@ accumulate_sibling_list (enum omp_region_type region_type, enum tree_code code, OMP_CLAUSE_SIZE (c2) = fold_build2_loc (OMP_CLAUSE_LOCATION (grp_end), MINUS_EXPR, ptrdiff_type_node, baddr, decladdr); - /* Insert after struct node. */ + /* Insert after struct node. If the mapping kind is GOMP_MAP_ATTACH, + we are only putting this here until the end of + omp_build_struct_sibling_lists, at which point we maybe adjust + the bias and move the node to the end of the clause list. */ OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (l); OMP_CLAUSE_CHAIN (l) = c2; } @@ -9978,7 +9997,8 @@ accumulate_sibling_list (enum omp_region_type region_type, enum tree_code code, in omp-low.c after it has been processed there.) */ if (*sc != grp_end && (OMP_CLAUSE_MAP_KIND (*sc) == GOMP_MAP_FIRSTPRIVATE_POINTER - || OMP_CLAUSE_MAP_KIND (*sc) == GOMP_MAP_FIRSTPRIVATE_REFERENCE)) + || OMP_CLAUSE_MAP_KIND (*sc) == GOMP_MAP_FIRSTPRIVATE_REFERENCE + || OMP_CLAUSE_MAP_KIND (*sc) == GOMP_MAP_ATTACH)) sc = &OMP_CLAUSE_CHAIN (*sc); for (; *sc != grp_end; sc = &OMP_CLAUSE_CHAIN (*sc)) if ((ptr || attach_detach) && sc == grp_start_p) @@ -10137,6 +10157,31 @@ accumulate_sibling_list (enum omp_region_type region_type, enum tree_code code, return continue_at; } +/* Return the base (pointer to struct or class) of a pointer-to-member access + expression, or NULL_TREE if EXPR is something else. */ + +static bool +omp_ptrmem_p (tree expr) +{ + if (TREE_CODE (expr) != INDIRECT_REF) + return false; + + expr = TREE_OPERAND (expr, 0); + + if (TREE_CODE (expr) == NON_LVALUE_EXPR) + expr = TREE_OPERAND (expr, 0); + + if (TREE_CODE (expr) == POINTER_PLUS_EXPR) + { + tree base = TREE_OPERAND (expr, 0); + STRIP_NOPS (base); + if (AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (base)))) + return true; + } + + return false; +} + /* Scan through GROUPS, and create sorted structure sibling lists without gimplifying. */ @@ -10199,7 +10244,14 @@ omp_build_struct_sibling_lists (enum tree_code code, STRIP_NOPS (decl); - if (TREE_CODE (decl) != COMPONENT_REF) + if (omp_ptrmem_p (decl)) + { + /* Pointer-to-member mapping types are not yet supported. */ + sorry_at (OMP_CLAUSE_LOCATION (c), "unsupported map expression %qE", + decl); + continue; + } + else if (TREE_CODE (decl) != COMPONENT_REF) continue; omp_mapping_group **wholestruct = NULL; @@ -10265,7 +10317,8 @@ omp_build_struct_sibling_lists (enum tree_code code, new_next = accumulate_sibling_list (region_type, code, struct_map_to_clause, - grp_start_p, grp_end, &inner); + *grpmap, grp_start_p, grp_end, + &inner); if (inner) { @@ -10295,6 +10348,52 @@ omp_build_struct_sibling_lists (enum tree_code code, } } + /* The list has been rearranged; "tail" might not point to the chain of the + last node any more. Make it do so. (Also, we have only been processing + "map" nodes, and non-map nodes might be present at the end of the list + too.) */ + while (*tail) + tail = &OMP_CLAUSE_CHAIN (*tail); + + /* Now we have finished building the struct sibling lists, reprocess + newly-added "attach" nodes: we need the address of the first + mapped element of each struct sibling list for the bias of the attach + operation -- not necessarily the base address of the whole struct. */ + if (struct_map_to_clause) + for (hash_map::iterator iter + = struct_map_to_clause->begin (); + iter != struct_map_to_clause->end (); + ++iter) + { + tree struct_node = (*iter).second; + gcc_assert (OMP_CLAUSE_CODE (struct_node) == OMP_CLAUSE_MAP); + tree attach = OMP_CLAUSE_CHAIN (struct_node); + + if (OMP_CLAUSE_CODE (attach) != OMP_CLAUSE_MAP + || OMP_CLAUSE_MAP_KIND (attach) != GOMP_MAP_ATTACH) + continue; + + /* This is the first sorted node in the struct sibling list. Use it + to recalculate the correct bias to use. + (&first_node - attach_decl). */ + tree first_node = OMP_CLAUSE_DECL (OMP_CLAUSE_CHAIN (attach)); + first_node = build_fold_addr_expr (first_node); + first_node = fold_convert (ptrdiff_type_node, first_node); + tree attach_decl = OMP_CLAUSE_DECL (attach); + //attach_decl = build_fold_addr_expr (attach_decl); + attach_decl = fold_convert (ptrdiff_type_node, attach_decl); + OMP_CLAUSE_SIZE (attach) + = fold_build2 (MINUS_EXPR, ptrdiff_type_node, first_node, + attach_decl); + + /* Remove GOMP_MAP_ATTACH node from after struct node. */ + OMP_CLAUSE_CHAIN (struct_node) = OMP_CLAUSE_CHAIN (attach); + /* ...and re-insert it at the end of our clause list. */ + *tail = attach; + OMP_CLAUSE_CHAIN (attach) = NULL_TREE; + tail = &OMP_CLAUSE_CHAIN (attach); + } + error_out: if (struct_map_to_clause) delete struct_map_to_clause; diff --git a/gcc/testsuite/c-c++-common/gomp/map-6.c b/gcc/testsuite/c-c++-common/gomp/map-6.c index 6ee59714847..c749db845b0 100644 --- a/gcc/testsuite/c-c++-common/gomp/map-6.c +++ b/gcc/testsuite/c-c++-common/gomp/map-6.c @@ -20,12 +20,12 @@ foo (void) ; #pragma omp target map (close a) /* { dg-error "'close' undeclared" "" { target c } } */ - /* { dg-error "'close' has not been declared" "" { target c++ } .-1 } */ + /* { dg-error "'close' was not declared in this scope" "" { target c++ } .-1 } */ /* { dg-error "expected '\\)' before 'a'" "" { target *-*-* } .-2 } */ ; #pragma omp target map (always a) /* { dg-error "'always' undeclared" "" { target c } } */ - /* { dg-error "'always' has not been declared" "" { target c++ } .-1 } */ + /* { dg-error "'always' was not declared in this scope" "" { target c++ } .-1 } */ /* { dg-error "expected '\\)' before 'a'" "" { target *-*-* } .-2 } */ ; diff --git a/gcc/testsuite/g++.dg/gomp/ind-base-3.C b/gcc/testsuite/g++.dg/gomp/ind-base-3.C new file mode 100644 index 00000000000..dbabaf7680c --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/ind-base-3.C @@ -0,0 +1,38 @@ +#include + +struct S { + int x[10]; +}; + +S * +choose (S *a, S *b, int c) +{ + if (c < 5) + return a; + else + return b; +} + +int main (int argc, char *argv[]) +{ + S a, b; + + for (int i = 0; i < 10; i++) + a.x[i] = b.x[i] = 0; + + for (int i = 0; i < 10; i++) + { +#pragma omp target map(choose(&a, &b, i)->x[:10]) +/* { dg-message {sorry, unimplemented: unsupported map expression 'choose\(\(& a\), \(& b\), i\)->S::x\[0\]'} "" { target *-*-* } .-1 } */ +/* { dg-message {sorry, unimplemented: unsupported map expression 'choose\(\(& a\), \(& b\), i\)'} "" { target *-*-* } .-2 } */ + for (int j = 0; j < 10; j++) + choose (&a, &b, i)->x[j]++; + } + + for (int i = 0; i < 10; i++) + assert (a.x[i] == 5 && b.x[i] == 5); + + return 0; +} + + diff --git a/gcc/testsuite/g++.dg/gomp/map-assignment-1.C b/gcc/testsuite/g++.dg/gomp/map-assignment-1.C new file mode 100644 index 00000000000..5979ec379f1 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/map-assignment-1.C @@ -0,0 +1,12 @@ +#include + +int main (int argc, char *argv[]) +{ + int a = 5, b = 2; +#pragma omp target map(a += b) + /* { dg-message {sorry, unimplemented: unsupported map expression '\(a = \(a \+ b\)\)'} "" { target *-*-* } .-1 } */ + { + a++; + } + return 0; +} diff --git a/gcc/testsuite/g++.dg/gomp/map-inc-1.C b/gcc/testsuite/g++.dg/gomp/map-inc-1.C new file mode 100644 index 00000000000..b469a4bd548 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/map-inc-1.C @@ -0,0 +1,10 @@ +int main (int argc, char *argv[]) +{ + int a = 5; +#pragma omp target map(++a) + /* { dg-message {sorry, unimplemented: unsupported map expression '\+\+ a'} "" { target *-*-* } .-1 } */ + { + a++; + } + return 0; +} diff --git a/gcc/testsuite/g++.dg/gomp/map-lvalue-ref-1.C b/gcc/testsuite/g++.dg/gomp/map-lvalue-ref-1.C new file mode 100644 index 00000000000..d720d4318ae --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/map-lvalue-ref-1.C @@ -0,0 +1,19 @@ +#include + +int glob = 10; + +int& foo () +{ + return glob; +} + +int main (int argc, char *argv[]) +{ +#pragma omp target map(foo()) + /* { dg-message {sorry, unimplemented: unsupported map expression 'foo\(\)'} "" { target *-*-* } .-1 } */ + { + foo()++; + } + assert (glob == 11); + return 0; +} diff --git a/gcc/testsuite/g++.dg/gomp/map-ptrmem-1.C b/gcc/testsuite/g++.dg/gomp/map-ptrmem-1.C new file mode 100644 index 00000000000..c4023f59fc6 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/map-ptrmem-1.C @@ -0,0 +1,37 @@ +#include + +struct S { + int x; + int *ptr; +}; + +int +main (int argc, char *argv[]) +{ + S s; + int S::* xp = &S::x; + int* S::* ptrp = &S::ptr; + + s.ptr = new int[64]; + + s.*xp = 6; + for (int i = 0; i < 64; i++) + (s.*ptrp)[i] = i; + +#pragma omp target map(s.*xp, s.*ptrp, (s.*ptrp)[:64]) + /* { dg-message {sorry, unimplemented: pointer-to-member mapping '\*\(\*\(\(\(int\*\*\)\(& s\)\) \+ \(\(sizetype\)ptrp\)\)\)' not supported} "" { target *-*-* } .-1 } */ + /* { dg-message {sorry, unimplemented: pointer-to-member mapping '\*\(\(\(int\*\*\)\(& s\)\) \+ \(\(sizetype\)ptrp\)\)' not supported} "" { target *-*-* } .-2 } */ + /* { dg-message {sorry, unimplemented: pointer-to-member mapping '\*\(\(\(int\*\)\(& s\)\) \+ \(\(sizetype\)xp\)\)' not supported} "" { target *-*-* } .-3 } */ +#pragma omp teams distribute parallel for + for (int i = 0; i < 64; i++) + { + (s.*xp)++; + (s.*ptrp)[i]++; + } + + assert (s.*xp == 70); + for (int i = 0; i < 64; i++) + assert ((s.*ptrp)[i] == i + 1); + + return 0; +} diff --git a/gcc/testsuite/g++.dg/gomp/map-ptrmem-2.C b/gcc/testsuite/g++.dg/gomp/map-ptrmem-2.C new file mode 100644 index 00000000000..fbf379da0eb --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/map-ptrmem-2.C @@ -0,0 +1,40 @@ +#include + +struct S { + int x; + int *ptr; +}; + +int +main (int argc, char *argv[]) +{ + S *s = new S; + int S::* xp = &S::x; + int* S::* ptrp = &S::ptr; + + s->ptr = new int[64]; + + s->*xp = 4; + for (int i = 0; i < 64; i++) + (s->*ptrp)[i] = i; + +#pragma omp target map(s->*xp, s->*ptrp, (s->*ptrp)[:64]) + /* { dg-message {sorry, unimplemented: pointer-to-member mapping '\*\(\(\(int\*\*\)s\) \+ \(\(sizetype\)ptrp\)\)' not supported} "" { target *-*-* } .-1 } */ + /* { dg-message {sorry, unimplemented: pointer-to-member mapping '\*\(\(\(int\*\)s\) \+ \(\(sizetype\)xp\)\)' not supported} "" { target *-*-* } .-2 } */ + /* { dg-message {sorry, unimplemented: pointer-to-member mapping '\*\(\*\(\(\(int\*\*\)s\) \+ \(\(sizetype\)ptrp\)\)\)' not supported} "" { target *-*-* } .-3 } */ +#pragma omp teams distribute parallel for + for (int i = 0; i < 64; i++) + { + (s->*xp)++; + (s->*ptrp)[i]++; + } + + assert (s->*xp == 68); + for (int i = 0; i < 64; i++) + assert ((s->*ptrp)[i] == i + 1); + + delete s->ptr; + delete s; + + return 0; +} diff --git a/gcc/testsuite/g++.dg/gomp/map-static-cast-lvalue-1.C b/gcc/testsuite/g++.dg/gomp/map-static-cast-lvalue-1.C new file mode 100644 index 00000000000..3af9668202c --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/map-static-cast-lvalue-1.C @@ -0,0 +1,17 @@ +#include + +int foo (int x) +{ +#pragma omp target map(static_cast(x)) + /* { dg-message {sorry, unimplemented: unsupported map expression '& x'} "" { target *-*-* } .-1 } */ + { + x += 3; + } + return x; +} + +int main (int argc, char *argv[]) +{ + assert (foo (5) == 8); + return 0; +} diff --git a/gcc/testsuite/g++.dg/gomp/map-ternary-1.C b/gcc/testsuite/g++.dg/gomp/map-ternary-1.C new file mode 100644 index 00000000000..7b365a909bb --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/map-ternary-1.C @@ -0,0 +1,20 @@ +#include + +int foo (bool yesno) +{ + int x = 5, y = 7; +#pragma omp target map(yesno ? x : y) + /* { dg-message {sorry, unimplemented: unsupported map expression '\(yesno \? x : y\)'} "" { target *-*-* } .-1 } */ + { + x += 3; + y += 5; + } + return yesno ? x : y; +} + +int main (int argc, char *argv[]) +{ + assert (foo (true) == 8); + assert (foo (false) == 12); + return 0; +} diff --git a/gcc/testsuite/g++.dg/gomp/member-array-2.C b/gcc/testsuite/g++.dg/gomp/member-array-2.C new file mode 100644 index 00000000000..e60bb5585a1 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/member-array-2.C @@ -0,0 +1,92 @@ +#include + +typedef int intarr100[100]; + +class C { + int arr[100]; + int *ptr; + +public: + C(); + ~C(); + void zero (); + void do_operation (); + void check (int, int); + intarr100 &get_arr () { return arr; } + int *get_ptr() { return ptr; } +}; + +C::C() +{ + ptr = new int[100]; + for (int i = 0; i < 100; i++) + arr[i] = 0; +} + +C::~C() +{ + delete ptr; +} + +void +C::zero () +{ + for (int i = 0; i < 100; i++) + arr[i] = ptr[i] = 0; +} + +void +C::do_operation () +{ +#pragma omp target map(arr, ptr, ptr[:100]) +#pragma omp teams distribute parallel for + for (int i = 0; i < 100; i++) + { + arr[i] = arr[i] + 3; + ptr[i] = ptr[i] + 5; + } +} + +void +C::check (int arrval, int ptrval) +{ + for (int i = 0; i < 100; i++) + { + assert (arr[i] == arrval); + assert (ptr[i] == ptrval); + } +} + +int +main (int argc, char *argv[]) +{ + C c; + + c.zero (); + c.do_operation (); + c.check (3, 5); + + /* It might sort of make sense to be able to do this, but we don't support + it for now. */ + #pragma omp target map(c.get_arr()[:100]) + /* { dg-message {sorry, unimplemented: unsupported map expression 'c\.C::get_arr\(\)\[0\]'} "" { target *-*-* } .-1 } */ + /* { dg-message {sorry, unimplemented: unsupported map expression 'c\.C::get_arr\(\)'} "" { target *-*-* } .-2 } */ + #pragma omp teams distribute parallel for + for (int i = 0; i < 100; i++) + c.get_arr()[i] += 2; + + c.check (5, 5); + + /* Same for this. */ + #pragma omp target map(c.get_ptr(), c.get_ptr()[:100]) + /* { dg-message {sorry, unimplemented: unsupported map expression 'c\.C::get_ptr\(\)'} "" { target *-*-* } .-1 } */ + /* { dg-message {sorry, unimplemented: unsupported map expression '\* c\.C::get_ptr\(\)'} "" { target *-*-* } .-2 } */ + #pragma omp teams distribute parallel for + for (int i = 0; i < 100; i++) + c.get_ptr()[i] += 3; + + c.check (5, 8); + + return 0; +} + diff --git a/gcc/testsuite/g++.dg/gomp/pr67522.C b/gcc/testsuite/g++.dg/gomp/pr67522.C index da8cb74d1fa..4a901ba68c7 100644 --- a/gcc/testsuite/g++.dg/gomp/pr67522.C +++ b/gcc/testsuite/g++.dg/gomp/pr67522.C @@ -12,7 +12,7 @@ foo (void) for (int i = 0; i < 16; i++) ; - #pragma omp target map (S[0:10]) // { dg-error "is not a variable in" } + #pragma omp target map (S[0:10]) // { dg-error "expected primary-expression before '\\\[' token" } ; #pragma omp task depend (inout: S[0:10]) // { dg-error "is not a variable in" } diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc index 666b7a70ea2..86fc5c090d6 100644 --- a/gcc/tree-pretty-print.cc +++ b/gcc/tree-pretty-print.cc @@ -2485,6 +2485,20 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags, } break; + case OMP_ARRAY_SECTION: + op0 = TREE_OPERAND (node, 0); + if (op_prio (op0) < op_prio (node)) + pp_left_paren (pp); + dump_generic_node (pp, op0, spc, flags, false); + if (op_prio (op0) < op_prio (node)) + pp_right_paren (pp); + pp_left_bracket (pp); + dump_generic_node (pp, TREE_OPERAND (node, 1), spc, flags, false); + pp_colon (pp); + dump_generic_node (pp, TREE_OPERAND (node, 2), spc, flags, false); + pp_right_bracket (pp); + break; + case CONSTRUCTOR: { unsigned HOST_WIDE_INT ix; diff --git a/gcc/tree.def b/gcc/tree.def index 62650b6934b..f015021e9dc 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -1310,6 +1310,9 @@ DEFTREECODE (OMP_ATOMIC_CAPTURE_NEW, "omp_atomic_capture_new", tcc_statement, 2) /* OpenMP clauses. */ DEFTREECODE (OMP_CLAUSE, "omp_clause", tcc_exceptional, 0) +/* An OpenMP array section. */ +DEFTREECODE (OMP_ARRAY_SECTION, "omp_array_section", tcc_expression, 3) + /* TRANSACTION_EXPR tree code. Operand 0: BODY: contains body of the transaction. */ DEFTREECODE (TRANSACTION_EXPR, "transaction_expr", tcc_expression, 1) diff --git a/libgomp/testsuite/libgomp.c++/ind-base-1.C b/libgomp/testsuite/libgomp.c++/ind-base-1.C new file mode 100644 index 00000000000..4566854e60a --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/ind-base-1.C @@ -0,0 +1,162 @@ +// { dg-do run } +// { dg-options "-fopenmp" } + +#include + +struct S +{ + int x[10]; +}; + +struct T +{ + struct S *s; +}; + +struct U +{ + struct T *t; +}; + +void +foo_siblist (void) +{ + U *u = new U; + u->t = new T; + u->t->s = new S; + 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) + 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); + delete u->t->s; + delete u->t; + delete u; +} + +void +foo (void) +{ + U *u = new U; + u->t = new T; + u->t->s = new S; + for (int i = 0; i < 10; i++) + u->t->s->x[i] = 0; +#pragma omp target map(*u, u->t, *(u->t), u->t->s, *u->t->s) + 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); + delete u->t->s; + delete u->t; + delete u; +} + +void +foo_tofrom (void) +{ + U *u = new U; + u->t = new T; + u->t->s = new S; + for (int i = 0; i < 10; i++) + u->t->s->x[i] = 0; +#pragma omp target map(u, *u, u->t, *(u->t), u->t->s, *u->t->s) + 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); + delete u->t->s; + delete u->t; + delete u; +} + +void +bar (void) +{ + U *u = new U; + U **up = &u; + u->t = new T; + u->t->s = new S; + for (int i = 0; i < 10; i++) + (*up)->t->s->x[i] = 0; +#pragma omp target map(*up, (*up)->t, *(*up)->t, (*up)->t->s, *(*up)->t->s) + for (int i = 0; i < 10; i++) + (*up)->t->s->x[i] = i * 3; + for (int i = 0; i < 10; i++) + assert ((*up)->t->s->x[i] == i * 3); + delete u->t->s; + delete u->t; + delete u; +} + +void +bar_pp (void) +{ + U *u = new U; + U **up = &u; + u->t = new T; + u->t->s = new S; + for (int i = 0; i < 10; i++) + (*up)->t->s->x[i] = 0; +#pragma omp target map(*up, **up, (*up)->t, *(*up)->t, (*up)->t->s, *(*up)->t->s) + for (int i = 0; i < 10; i++) + (*up)->t->s->x[i] = i * 3; + for (int i = 0; i < 10; i++) + assert ((*up)->t->s->x[i] == i * 3); + delete u->t->s; + delete u->t; + delete u; +} + +void +bar_tofrom (void) +{ + U *u = new U; + U **up = &u; + u->t = new T; + u->t->s = new S; + for (int i = 0; i < 10; i++) + (*up)->t->s->x[i] = 0; +#pragma omp target map(*up, up, (*up)->t, *(*up)->t, (*up)->t->s, *(*up)->t->s) + for (int i = 0; i < 10; i++) + (*up)->t->s->x[i] = i * 3; + for (int i = 0; i < 10; i++) + assert ((*up)->t->s->x[i] == i * 3); + delete u->t->s; + delete u->t; + delete u; +} + +void +bar_tofrom_pp (void) +{ + U *u = new U; + U **up = &u; + u->t = new T; + u->t->s = new S; + for (int i = 0; i < 10; i++) + (*up)->t->s->x[i] = 0; +#pragma omp target map(**up, *up, up, (*up)->t, *(*up)->t, (*up)->t->s, \ + *(*up)->t->s) + for (int i = 0; i < 10; i++) + (*up)->t->s->x[i] = i * 3; + for (int i = 0; i < 10; i++) + assert ((*up)->t->s->x[i] == i * 3); + delete u->t->s; + delete u->t; + delete u; +} + +int main (int argc, char *argv[]) +{ + foo_siblist (); + foo (); + foo_tofrom (); + bar (); + bar_pp (); + bar_tofrom (); + bar_tofrom_pp (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/ind-base-2.C b/libgomp/testsuite/libgomp.c++/ind-base-2.C new file mode 100644 index 00000000000..706a1205c00 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/ind-base-2.C @@ -0,0 +1,49 @@ +// { dg-do run } +// { dg-options "-fopenmp" } + +#include + +struct S +{ + int x[10]; +}; + +struct T +{ + struct S ***s; +}; + +struct U +{ + struct T **t; +}; + +void +foo (void) +{ + U *u = new U; + T *real_t = new T; + S *real_s = new 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); + delete real_s; + delete real_t; + delete u; +} + +int main (int argc, char *argv[]) +{ + foo (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/map-comma-1.C b/libgomp/testsuite/libgomp.c++/map-comma-1.C new file mode 100644 index 00000000000..ee03c5ac1aa --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/map-comma-1.C @@ -0,0 +1,15 @@ +/* { dg-do run } */ + +#include + +int main (int argc, char *argv[]) +{ + int a = 5, b = 7; +#pragma omp target map((a, b)) + { + a++; + b++; + } + assert (a == 5 && b == 8); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/map-rvalue-ref-1.C b/libgomp/testsuite/libgomp.c++/map-rvalue-ref-1.C new file mode 100644 index 00000000000..93811da4000 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/map-rvalue-ref-1.C @@ -0,0 +1,22 @@ +/* { dg-do run } */ + +#include + +int foo (int &&x) +{ + int y; +#pragma omp target map(x, y) + { + x++; + y = x; + } + return y; +} + +int main (int argc, char *argv[]) +{ + int y = 5; + y = foo (y + 3); + assert (y == 9); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/struct-ref-1.C b/libgomp/testsuite/libgomp.c++/struct-ref-1.C new file mode 100644 index 00000000000..d3874650017 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/struct-ref-1.C @@ -0,0 +1,97 @@ +// { dg-do run } +// { dg-options "-fopenmp" } + +#include + +struct S +{ + int x[10]; +}; + +void +foo (S *s, int x) +{ + S *&r = s; + for (int i = 0; i < x; i++) + s[0].x[i] = s[1].x[i] = 0; + #pragma omp target map (s, x) + ; + #pragma omp target map (s[0], x) + for (int i = 0; i < x; i++) + s[0].x[i] = i; + #pragma omp target map (s[1], x) + for (int i = 0; i < x; i++) + s[1].x[i] = i * 2; + for (int i = 0; i < x; i++) + { + assert (s[0].x[i] == i); + assert (s[1].x[i] == i * 2); + s[0].x[i] = 0; + s[1].x[i] = 0; + } + #pragma omp target map (r, x) + ; + #pragma omp target map (r[0], x) + for (int i = 0; i < x; i++) + r[0].x[i] = i; + #pragma omp target map (r[1], x) + for (int i = 0; i < x; i++) + r[1].x[i] = i * 2; + for (int i = 0; i < x; i++) + { + assert (r[0].x[i] == i); + assert (r[1].x[i] == i * 2); + } +} + +template +struct T +{ + int x[N]; +}; + +template +void +bar (T *t, int x) +{ + T *&r = t; + for (int i = 0; i < x; i++) + t[0].x[i] = t[1].x[i] = 0; + #pragma omp target map (t, x) + ; + #pragma omp target map (t[0], x) + for (int i = 0; i < x; i++) + t[0].x[i] = i; + #pragma omp target map (t[1], x) + for (int i = 0; i < x; i++) + t[1].x[i] = i * 2; + for (int i = 0; i < x; i++) + { + assert (t[0].x[i] == i); + assert (t[1].x[i] == i * 2); + t[0].x[i] = 0; + t[1].x[i] = 0; + } + #pragma omp target map (r, x) + ; + #pragma omp target map (r[0], x) + for (int i = 0; i < x; i++) + r[0].x[i] = i; + #pragma omp target map (r[1], x) + for (int i = 0; i < x; i++) + r[1].x[i] = i * 2; + for (int i = 0; i < x; i++) + { + assert (r[0].x[i] == i); + assert (r[1].x[i] == i * 2); + } +} + +int main (int argc, char *argv[]) +{ + S s[2]; + foo (s, 10); + T<10> t[2]; + bar (t, 10); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/array-field-1.c b/libgomp/testsuite/libgomp.c-c++-common/array-field-1.c new file mode 100644 index 00000000000..6dd8b5c48e1 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/array-field-1.c @@ -0,0 +1,35 @@ +/* { dg-do run } */ + +#include +#include +#include + +#define N 16 + +struct Z { + int *ptr; + int arr[N]; + int c; +}; + +int main (int argc, char *argv[]) +{ + struct Z *myz; + myz = (struct Z *) calloc (1, sizeof *myz); + +#pragma omp target map(tofrom:myz->arr[0:N], myz->c) + { + for (int i = 0; i < N; i++) + myz->arr[i]++; + myz->c++; + } + + for (int i = 0; i < N; i++) + assert (myz->arr[i] == 1); + assert (myz->c == 1); + + free (myz); + + return 0; +} + diff --git a/libgomp/testsuite/libgomp.c-c++-common/array-of-struct-1.c b/libgomp/testsuite/libgomp.c-c++-common/array-of-struct-1.c new file mode 100644 index 00000000000..726eede6c31 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/array-of-struct-1.c @@ -0,0 +1,65 @@ +/* { dg-do run } */ + +#include +#include +#include + +#define N 16 + +/* NOTE: This test is the same as array-of-struct-2.c, except the fields of + this struct are in a different order. */ + +struct Z { + int arr[N]; + int *ptr; + int c; +}; + +void +foo (struct Z *zarr, int len) +{ +#pragma omp target map(to:zarr, zarr[5].ptr) map(tofrom:zarr[5].ptr[0:len]) + { + for (int i = 0; i < len; i++) + zarr[5].ptr[i]++; + } + +#pragma omp target map(to:zarr) map(tofrom:zarr[4].arr[0:len]) + { + for (int i = 0; i < len; i++) + zarr[4].arr[i]++; + } + +#pragma omp target map (to:zarr[3].ptr) map(tofrom:zarr[3].ptr[0:len]) + { + for (int i = 0; i < len; i++) + zarr[3].ptr[i]++; + } + +#pragma omp target map(tofrom:zarr[2].arr[0:len]) + { + for (int i = 0; i < len; i++) + zarr[2].arr[i]++; + } +} + +int main (int argc, char *argv[]) +{ + struct Z zs[10]; + memset (zs, 0, sizeof zs); + + for (int i = 0; i < 10; i++) + zs[i].ptr = (int *) calloc (N, sizeof (int)); + + foo (zs, N); + + for (int i = 0; i < N; i++) + { + assert (zs[2].arr[i] == 1); + assert (zs[4].arr[i] == 1); + assert (zs[3].ptr[i] == 1); + assert (zs[5].ptr[i] == 1); + } + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/array-of-struct-2.c b/libgomp/testsuite/libgomp.c-c++-common/array-of-struct-2.c new file mode 100644 index 00000000000..c4b77cd13f1 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/array-of-struct-2.c @@ -0,0 +1,65 @@ +/* { dg-do run } */ + +#include +#include +#include + +#define N 16 + +/* NOTE: This test is the same as array-of-struct-1.c, except the fields of + this struct are in a different order. */ + +struct Z { + int *ptr; + int arr[N]; + int c; +}; + +void +foo (struct Z *zarr, int len) +{ +#pragma omp target map(to:zarr, zarr[5].ptr) map(tofrom:zarr[5].ptr[0:len]) + { + for (int i = 0; i < len; i++) + zarr[5].ptr[i]++; + } + +#pragma omp target map(to:zarr) map(tofrom:zarr[4].arr[0:len]) + { + for (int i = 0; i < len; i++) + zarr[4].arr[i]++; + } + +#pragma omp target map (to:zarr[3].ptr) map(tofrom:zarr[3].ptr[0:len]) + { + for (int i = 0; i < len; i++) + zarr[3].ptr[i]++; + } + +#pragma omp target map(tofrom:zarr[2].arr[0:len]) + { + for (int i = 0; i < len; i++) + zarr[2].arr[i]++; + } +} + +int main (int argc, char *argv[]) +{ + struct Z zs[10]; + memset (zs, 0, sizeof zs); + + for (int i = 0; i < 10; i++) + zs[i].ptr = (int *) calloc (N, sizeof (int)); + + foo (zs, N); + + for (int i = 0; i < N; i++) + { + assert (zs[2].arr[i] == 1); + assert (zs[4].arr[i] == 1); + assert (zs[3].ptr[i] == 1); + assert (zs[5].ptr[i] == 1); + } + + return 0; +} -- 2.29.2